delete test, add combined type

This commit is contained in:
zongor 2025-06-08 15:24:43 -04:00
parent cdf21dd5cf
commit 2817e940e1
4 changed files with 231 additions and 387 deletions

View File

@ -1,176 +0,0 @@
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#define MEMORY_SIZE 65536 // 64KB memory (adjustable)
uint32_t memory[MEMORY_SIZE]; // Memory array
#define DEBUG_PRINT \
printf("dest[%d]=%d, src1[%d]=%d, src2[%d]=%d\n", dest_addr, \
memory[dest_addr], src1_addr, memory[src1_addr], src2_addr, \
memory[src2_addr]);
typedef enum {
OP_HALT, // terminate execution
OP_ADD, // dest = src1 + src2
OP_SUB, // dest = src1 - src2
OP_MOV, // dest = src1
OP_JMP, // jump to address src1 unconditionally
OP_JGZ, // jump to address dest if src1 > 0
OP_READ_STRING,
OP_PRINT_STRING,
} Opcode;
uint8_t get_char(uint32_t word, int index) {
return (word >> (8 * index)) & 0xFF;
}
uint32_t set_char(uint32_t word, int index, uint8_t ch) {
return (word & ~(0xFF << (8 * index))) | (ch << (8 * index));
}
void run_vm() {
uint32_t pc = 0; // Program counter
while (pc < MEMORY_SIZE - 4) {
// Fetch instruction
Opcode opcode = memory[pc];
uint32_t src1_addr = memory[pc + 1];
uint32_t src2_addr = memory[pc + 2];
uint32_t dest_addr = memory[pc + 3];
pc += 4; // Advance to next instruction
// Validate addresses (safety check)
if (src1_addr >= MEMORY_SIZE || src2_addr >= MEMORY_SIZE ||
dest_addr >= MEMORY_SIZE) {
printf("Invalid memory address!\n");
exit(1);
}
printf("opcode: ");
// Execute instruction
switch (opcode) {
case OP_ADD:
printf("ADD, ");
DEBUG_PRINT
memory[dest_addr] = memory[src1_addr] + memory[src2_addr];
break;
case OP_SUB:
printf("SUB, ");
DEBUG_PRINT
memory[dest_addr] = memory[src1_addr] - memory[src2_addr];
break;
case OP_HALT:
printf("HALT, ");
return;
case OP_MOV:
printf("MOV, ");
DEBUG_PRINT
memory[dest_addr] = memory[src1_addr];
break;
case OP_JMP:
printf("JMP, ");
DEBUG_PRINT
pc = src1_addr; // Jump to address
break;
case OP_JGZ: {
printf("JGZ, ");
DEBUG_PRINT
uint32_t value = memory[src1_addr];
uint32_t jump_target = src2_addr;
// Branchless greater-than-zero check
int32_t mask = -((uint32_t)(value > 0));
pc = (jump_target & mask) | (pc & ~mask);
break;
}
case OP_PRINT_STRING: {
printf("PRINT_STR, ");
uint32_t string_addr = src1_addr;
int i = 0;
while (1) {
uint32_t word = memory[string_addr + (i++)];
for (int j = 0; j < 4; j++) {
char ch = (word >> (8 * j)) & 0xFF;
if (ch == '\0')
goto done;
putchar(ch);
}
}
done:
putchar('\n');
break;
}
case OP_READ_STRING: {
printf("READ_STR, ");
uint32_t buffer_addr = dest_addr;
char buffer[4];
int word_index = 0;
int char_index = 0;
while (1) {
int ch = getchar();
if (ch == '\n' || ch == EOF) {
// Store null terminator
uint32_t word = memory[buffer_addr + word_index];
word = set_char(word, char_index, '\0');
memory[buffer_addr + word_index] = word;
break;
}
uint32_t word = memory[buffer_addr + word_index];
word = set_char(word, char_index, ch);
memory[buffer_addr + word_index] = word;
char_index++;
if (char_index == 4) {
char_index = 0;
word_index++;
}
}
break;
}
default:
DEBUG_PRINT
printf("Unknown opcode: %d\n", opcode);
exit(1);
}
}
}
int main() {
// Initialize memory
memory[0] = OP_READ_STRING;
memory[1] = 0; // unused
memory[2] = 0; // unused
memory[3] = 104; // dest
memory[4] = OP_ADD;
memory[5] = 102; // A (src1)
memory[6] = 103; // B (src2)
memory[7] = 103; // C (dest)
memory[8] = OP_SUB;
memory[9] = 100; // counter (src1)
memory[10] = 101; // value (src2)
memory[11] = 100; // counter (dest)
memory[12] = OP_JGZ;
memory[13] = 100; // (src1)
memory[14] = 4; // (src2)
memory[15] = 4; // (dest)
memory[16] = OP_PRINT_STRING;
memory[17] = 104; // String address
memory[18] = 0; // Unused
memory[19] = 0; // Unused
memory[20] = OP_HALT; // Terminate after ADD
memory[100] = 5; // Value of A
memory[101] = 1; // Value of B
memory[102] = 5;
memory[103] = 5;
/* memcpy(&memory[104], "hell", 4); */
/* memcpy(&memory[105], "o\n\0\0", 4); */
run_vm();
printf("Result at address 103: %u\n", memory[103]); // Output: 12
return 0;
}

View File

@ -1,210 +0,0 @@
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
// Q16.16 fixed-point macros
#define Q16_16_SCALE 16
#define Q16_16_FRACTION_MASK 0x0000FFFF
#define TO_Q16_16(x) \
((int32_t)((x) << Q16_16_SCALE)) // Convert integer to Q16.16
#define FROM_Q16_16(x) \
((int32_t)((x) >> Q16_16_SCALE)) // Convert Q16.16 to integer
#define MEMORY_SIZE 65536
int32_t memory[MEMORY_SIZE]; // Changed to signed for fixed-point support
typedef enum { OP_ADD, OP_MOV, OP_JMP, OP_HALT } Opcode;
// Convert string to Q16.16 fixed-point
int32_t string_to_q16_16(const char *str) {
int32_t result = 0;
int sign = 1;
// Handle sign
if (*str == '-') {
sign = -1;
str++;
}
// Parse integer part
int32_t integer_part = 0;
while (*str != '.' && *str != '\0') {
if (*str < '0' || *str > '9') {
return 0; // Invalid character
}
integer_part = integer_part * 10 + (*str - '0');
str++;
}
// Clamp integer part to 16-bit range
if (integer_part > 32767) {
integer_part = 32767; // Overflow clamp
}
// Parse fractional part
uint32_t frac_digits = 0;
int frac_count = 0;
if (*str == '.') {
str++; // Skip decimal point
while (*str != '\0' && frac_count < 6) {
if (*str < '0' || *str > '9') {
break;
}
frac_digits = frac_digits * 10 + (*str - '0');
frac_count++;
str++;
}
}
// Scale fractional part to Q16.16
// frac_q16 = (frac_digits * 65536 + 500000) / 1000000
// This avoids floating-point by using integer arithmetic
uint32_t scaled_frac = 0;
if (frac_count > 0) {
// Pad with zeros if less than 6 digits
while (frac_count < 6) {
frac_digits *= 10;
frac_count++;
}
// Compute scaled fractional part with rounding
scaled_frac = (frac_digits * 65536 + 500000) / 1000000;
if (scaled_frac > 0xFFFF) {
scaled_frac = 0xFFFF; // Clamp to 16-bit range
}
}
// Combine integer and fractional parts
result = (integer_part << Q16_16_SCALE) | (scaled_frac & Q16_16_FRACTION_MASK);
return result * sign;
}
// Convert Q16.16 to string using integer-only arithmetic
int q16_16_to_string(int32_t value, char *buffer, size_t size) {
if (size < 13) { // Minimum buffer size for "-32768.000000\0"
if (size > 0)
buffer[0] = '\0';
return -1; // Buffer too small
}
char *buf = buffer;
size_t remaining = size;
// Handle sign
if (value < 0) {
*buf++ = '-';
value = -value;
remaining--;
}
// Extract integer and fractional parts
int32_t integer_part = value >> Q16_16_SCALE;
uint32_t frac = value & Q16_16_FRACTION_MASK;
// Convert integer part to string
char int_buf[11]; // Max 10 digits for 32-bit int
char *int_end = int_buf + sizeof(int_buf);
char *int_ptr = int_end;
// Special case for zero
if (integer_part == 0) {
*--int_ptr = '0';
} else {
while (integer_part > 0 && int_ptr > int_buf) {
*--int_ptr = '0' + (integer_part % 10);
integer_part /= 10;
}
}
// Copy integer part to output buffer
while (int_ptr < int_end && remaining > 1) {
*buf++ = *int_ptr++;
remaining--;
}
// Add decimal point
if (remaining > 7) { // Need space for .000000
*buf++ = '.';
remaining--;
} else {
if (remaining > 0)
*buf = '\0';
return size - remaining; // Truncate if insufficient space
}
// Convert fractional part to 6 digits
for (int i = 0; i < 6 && remaining > 1; i++) {
frac *= 10;
uint32_t digit = frac >> 16;
frac &= 0xFFFF;
*buf++ = '0' + digit;
remaining--;
}
// Null-terminate
*buf = '\0';
return buf - buffer; // Return length written
}
void run_vm() {
uint32_t pc = 0;
while (1) {
Opcode opcode = memory[pc];
uint32_t src1_addr = memory[pc + 1];
uint32_t src2_addr = memory[pc + 2];
uint32_t dest_addr = memory[pc + 3];
pc += 4;
if (src1_addr >= MEMORY_SIZE || src2_addr >= MEMORY_SIZE ||
dest_addr >= MEMORY_SIZE) {
printf("Invalid memory address!\n");
exit(1);
}
switch (opcode) {
case OP_ADD:
// Q16.16 addition requires no scaling adjustment
memory[dest_addr] = memory[src1_addr] + memory[src2_addr];
break;
case OP_MOV:
// Direct copy preserves fixed-point representation
memory[dest_addr] = memory[src1_addr];
break;
case OP_JMP:
pc = src1_addr;
break;
case OP_HALT:
return;
default:
printf("Unknown opcode: %d\n", opcode);
exit(1);
}
}
}
int main() {
// Initialize memory with Q16.16 values
memory[0] = OP_ADD;
memory[1] = 100;
memory[2] = 101;
memory[3] = 102;
const char *input = "-5.0";
memory[100] = string_to_q16_16(input); // Convert "-5.0" to Q16.16
const char *input2 = "10.0";
memory[101] = string_to_q16_16(input2); // Convert "10.0" to Q16.16
memory[4] = OP_HALT;
run_vm();
char buffer[13]; // Sufficient for Q16.16 format
// Convert result back to integer
q16_16_to_string(memory[102], buffer, sizeof(buffer));
printf("Result at address 102: %s\n", buffer); // Output: 5.0
return 0;
}

View File

@ -1,6 +1,6 @@
# Compiler and flags
CC = gcc
CFLAGS += -std=c11 -g -Wall -Wextra -Werror -Wno-unused-parameter
CFLAGS += -std=c89 -g -Wall -Wextra -Werror -Wno-unused-parameter
LDFLAGS +=
LDLIBS +=

230
src/vm.c Normal file
View File

@ -0,0 +1,230 @@
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#define MEMORY_SIZE 65536 /* 64KB memory (adjustable) */
typedef union {
float f;
uint32_t u;
} FloatUint32Union;
FloatUint32Union memory[MEMORY_SIZE]; /* Memory array */
typedef enum {
OP_HALT, /* terminate execution */
OP_ADD, /* dest = src1 + src2 */
OP_SUB, /* dest = src1 - src2 */
OP_MUL, /* dest = src1 * src2 */
OP_DIV, /* dest = src1 / src2 */
OP_ADD_F32, /* dest = src1 + src2 */
OP_SUB_F32, /* dest = src1 - src2 */
OP_MUL_F32, /* dest = src1 * src2 */
OP_DIV_F32, /* dest = src1 / src2 */
OP_MOV, /* dest = src1 */
OP_JMP, /* jump to address src1 unconditionally */
OP_JGZ, /* jump to address dest if src1 > 0 */
OP_READ_STRING,
OP_PRINT_STRING,
} Opcode;
uint8_t get_char(uint32_t word, int index) {
return (word >> (8 * index)) & 0xFF;
}
uint32_t set_char(uint32_t word, int index, uint8_t ch) {
return (word & ~(0xFF << (8 * index))) | (ch << (8 * index));
}
void run_vm() {
uint32_t pc = 0; /* Program counter */
while (pc < MEMORY_SIZE - 4) {
Opcode opcode = memory[pc].u;
uint32_t src1_addr = memory[pc + 1].u;
uint32_t src2_addr = memory[pc + 2].u;
uint32_t dest_addr = memory[pc + 3].u;
pc += 4; /* Advance to next instruction */
if (src1_addr >= MEMORY_SIZE || src2_addr >= MEMORY_SIZE ||
dest_addr >= MEMORY_SIZE) {
printf("Invalid memory address!\n");
exit(1);
}
switch (opcode) {
case OP_ADD:
memory[dest_addr].u = memory[src1_addr].u + memory[src2_addr].u;
printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr,
memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr,
memory[dest_addr].u);
break;
case OP_SUB:
memory[dest_addr].u = memory[src1_addr].u - memory[src2_addr].u;
printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr,
memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr,
memory[dest_addr].u);
break;
case OP_MUL:
memory[dest_addr].u = memory[src1_addr].u * memory[src2_addr].u;
printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr,
memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr,
memory[dest_addr].u);
break;
case OP_DIV:
memory[dest_addr].u = memory[src1_addr].u / memory[src2_addr].u;
printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr,
memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr,
memory[dest_addr].u);
break;
case OP_ADD_F32:
memory[dest_addr].f = memory[src1_addr].f + memory[src2_addr].f;
printf("ADD;src1[%d]:%f;src2[%d]:%f;dest[%d]:%f\n", src1_addr,
memory[src1_addr].f, src2_addr, memory[src2_addr].f, dest_addr,
memory[dest_addr].f);
break;
case OP_SUB_F32:
memory[dest_addr].f = memory[src1_addr].f - memory[src2_addr].f;
printf("ADD;src1[%d]:%f;src2[%d]:%f;dest[%d]:%f\n", src1_addr,
memory[src1_addr].f, src2_addr, memory[src2_addr].f, dest_addr,
memory[dest_addr].f);
break;
case OP_MUL_F32:
memory[dest_addr].f = memory[src1_addr].f * memory[src2_addr].f;
printf("ADD;src1[%d]:%f;src2[%d]:%f;dest[%d]:%f\n", src1_addr,
memory[src1_addr].f, src2_addr, memory[src2_addr].f, dest_addr,
memory[dest_addr].f);
break;
case OP_DIV_F32:
if (memory[src2_addr].f == 0.0f) {
printf("Division by zero error at address %d\n", pc - 4);
exit(1);
}
memory[dest_addr].f = memory[src1_addr].f / memory[src2_addr].f;
printf("ADD;src1[%d]:%f;src2[%d]:%f;dest[%d]:%f\n", src1_addr,
memory[src1_addr].f, src2_addr, memory[src2_addr].f, dest_addr,
memory[dest_addr].f);
break;
case OP_HALT:
printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr,
memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr,
memory[dest_addr].u);
return;
case OP_MOV:
printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr,
memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr,
memory[dest_addr].u);
memory[dest_addr] = memory[src1_addr];
break;
case OP_JMP:
printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr,
memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr,
memory[dest_addr].u);
pc = src1_addr; /* Jump to address */
break;
case OP_JGZ: {
printf("ADD;src1[%d]:%d;src2[%d]:%d;dest[%d]:%d\n", src1_addr,
memory[src1_addr].u, src2_addr, memory[src2_addr].u, dest_addr,
memory[dest_addr].u);
uint32_t value = memory[src1_addr].u;
uint32_t jump_target = src2_addr;
/* Branchless greater-than-zero check */
int32_t mask = -((uint32_t)(value > 0));
pc = (jump_target & mask) | (pc & ~mask);
break;
}
case OP_PRINT_STRING: {
printf("PRINT_STRING;");
uint32_t string_addr = src1_addr;
int i = 0;
while (1) {
int j = 0;
uint32_t word = memory[string_addr + (i++)].u;
for (j = 0; j < 4; j++) {
char ch = (word >> (8 * j)) & 0xFF;
if (ch == '\0')
goto done;
putchar(ch);
}
}
done:
putchar('\n');
break;
}
case OP_READ_STRING: {
printf("> ");
uint32_t buffer_addr = dest_addr;
int word_index = 0;
int char_index = 0;
while (1) {
int ch = getchar();
if (ch == '\n' || ch == EOF) {
/* Store null terminator */
uint32_t word = memory[buffer_addr + word_index].u;
word = set_char(word, char_index, '\0');
memory[buffer_addr + word_index].u = word;
break;
}
uint32_t word = memory[buffer_addr + word_index].u;
word = set_char(word, char_index, ch);
memory[buffer_addr + word_index].u = word;
char_index++;
if (char_index == 4) {
char_index = 0;
word_index++;
}
}
break;
}
default:
printf("Unknown opcode: %d\n", opcode);
return;
}
}
}
int main() {
memory[0].u = OP_READ_STRING;
memory[1].u = 0;
memory[2].u = 0;
memory[3].u = 104;
memory[4].u = OP_ADD_F32;
memory[5].u = 102;
memory[6].u = 103;
memory[7].u = 103;
memory[8].u = OP_SUB;
memory[9].u = 100;
memory[10].u = 101;
memory[11].u = 100;
memory[12].u = OP_JGZ;
memory[13].u = 100;
memory[14].u = 4;
memory[15].u = 4;
memory[16].u = OP_PRINT_STRING;
memory[17].u = 104;
memory[18].u = 0;
memory[19].u = 0;
memory[20].u = OP_HALT;
memory[100].u = 5;
memory[101].u = 1;
memory[102].f = 5.f;
memory[103].f = 5.f;
run_vm();
printf("Dest at address 103: %f\n", memory[103].f);
return 0;
}