2017-12-02 13:05:53 -06:00
|
|
|
/*
|
|
|
|
* vm_segment.c
|
|
|
|
*
|
2017-12-08 22:12:31 -06:00
|
|
|
* The functions here allow you to allocate generic blocks of memory (or
|
|
|
|
* "segments") for use anywhere else in the software. They can be used
|
|
|
|
* to represent machine memory, removable media (like floppy disks),
|
|
|
|
* etc.
|
2017-12-02 13:05:53 -06:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2017-11-21 23:24:51 -06:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "log.h"
|
|
|
|
#include "vm_segment.h"
|
|
|
|
|
2017-12-02 13:05:53 -06:00
|
|
|
/*
|
|
|
|
* Create a new segment, such that it contains a number of bytes indicated
|
|
|
|
* by `size`.
|
|
|
|
*/
|
2017-11-21 23:24:51 -06:00
|
|
|
vm_segment *
|
|
|
|
vm_segment_create(size_t size)
|
|
|
|
{
|
2017-12-02 13:05:53 -06:00
|
|
|
vm_segment *segment;
|
2017-11-21 23:24:51 -06:00
|
|
|
|
|
|
|
// Allocate memory for the current memory segment.
|
2017-12-02 13:05:53 -06:00
|
|
|
segment = malloc(sizeof(vm_segment));
|
2017-11-21 23:24:51 -06:00
|
|
|
|
|
|
|
// Ack! We couldn't get the memory we wanted. Let's bail.
|
2017-12-02 13:05:53 -06:00
|
|
|
if (segment == NULL) {
|
|
|
|
log_critical("Couldn't allocate enough space for vm_segment");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
segment->memory = malloc(sizeof(vm_8bit) * size);
|
|
|
|
if (segment->memory == NULL) {
|
2017-11-21 23:24:51 -06:00
|
|
|
log_critical("Couldn't allocate enough space for vm_segment");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-12-02 13:05:53 -06:00
|
|
|
segment->size = size;
|
2017-11-21 23:24:51 -06:00
|
|
|
|
2017-12-02 13:05:53 -06:00
|
|
|
return segment;
|
2017-11-21 23:24:51 -06:00
|
|
|
}
|
|
|
|
|
2017-12-02 13:05:53 -06:00
|
|
|
/*
|
|
|
|
* Free the memory consumed by a given segment.
|
|
|
|
*/
|
2017-11-21 23:24:51 -06:00
|
|
|
void
|
2017-12-02 13:05:53 -06:00
|
|
|
vm_segment_free(vm_segment *segment)
|
|
|
|
{
|
|
|
|
free(segment->memory);
|
|
|
|
free(segment);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the byte in `segment`, at `index`, to the given `value`. Our
|
|
|
|
* bounds-checking here will _crash_ the program if we are
|
|
|
|
* out-of-bounds.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
vm_segment_set(vm_segment *segment, size_t index, vm_8bit value)
|
2017-11-21 23:24:51 -06:00
|
|
|
{
|
|
|
|
// Some bounds checking.
|
|
|
|
if (!vm_segment_bounds_check(segment, index)) {
|
|
|
|
log_critical(
|
|
|
|
"Attempt to set segment index (%d) greater than bounds (%d)",
|
|
|
|
index,
|
|
|
|
segment->size);
|
|
|
|
|
|
|
|
// We prefer to exit in this scenario, rather than try to
|
|
|
|
// "handle" it with an overflow, because we would rather a crash
|
|
|
|
// over ill-defined behavior.
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
segment->memory[index] = value;
|
|
|
|
}
|
|
|
|
|
2017-12-02 13:05:53 -06:00
|
|
|
/*
|
|
|
|
* Return the byte in `segment` at the given `index` point. Our
|
|
|
|
* bounds-checking will _crash_ the program if an index is requested out
|
|
|
|
* of bounds.
|
|
|
|
*/
|
|
|
|
vm_8bit
|
2017-11-21 23:24:51 -06:00
|
|
|
vm_segment_get(vm_segment *segment, size_t index)
|
|
|
|
{
|
|
|
|
if (!vm_segment_bounds_check(segment, index)) {
|
|
|
|
log_critical(
|
|
|
|
"Attempt to set segment index (%d) greater than bounds (%d)",
|
|
|
|
index,
|
|
|
|
segment->size);
|
|
|
|
|
|
|
|
// See vm_segment_set() for a justification of this behavior.
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return segment->memory[index];
|
|
|
|
}
|
|
|
|
|
2017-12-02 13:05:53 -06:00
|
|
|
/*
|
|
|
|
* Copy a set of bytes from `src` (at `src_index`) to `dest` (at
|
|
|
|
* `dest_index`), such that the range is `length` bytes long.
|
|
|
|
*/
|
2017-11-21 23:24:51 -06:00
|
|
|
void
|
2017-12-02 13:05:53 -06:00
|
|
|
vm_segment_copy(vm_segment *dest,
|
|
|
|
vm_segment *src,
|
2017-11-21 23:24:51 -06:00
|
|
|
size_t dest_index,
|
2017-12-02 13:05:53 -06:00
|
|
|
size_t src_index,
|
2017-11-21 23:24:51 -06:00
|
|
|
size_t length)
|
|
|
|
{
|
|
|
|
if (src_index + length >= src->size) {
|
|
|
|
log_critical(
|
|
|
|
"Attempt to copy beyond bounds of vm_segment (%d + %d >= %d)",
|
|
|
|
src_index,
|
|
|
|
length,
|
|
|
|
src->size);
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dest_index + length >= dest->size) {
|
|
|
|
log_critical(
|
|
|
|
"Attempt to copy beyond bounds of vm_segment (%d + %d >= %d)",
|
|
|
|
dest_index,
|
|
|
|
length,
|
|
|
|
dest->size);
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(dest->memory + dest_index,
|
|
|
|
src->memory + src_index,
|
|
|
|
length * sizeof(src->memory[src_index]));
|
|
|
|
}
|