delete test, add combined type
This commit is contained in:
parent
cdf21dd5cf
commit
2817e940e1
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Compiler and flags
|
# Compiler and flags
|
||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS += -std=c11 -g -Wall -Wextra -Werror -Wno-unused-parameter
|
CFLAGS += -std=c89 -g -Wall -Wextra -Werror -Wno-unused-parameter
|
||||||
LDFLAGS +=
|
LDFLAGS +=
|
||||||
LDLIBS +=
|
LDLIBS +=
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue