~vertigo/forthbox

6045d38d963574cf61099f2e5ca2b2e47d11828b — Samuel A. Falvo II 4 months ago bffc748
Refactor
4 files changed, 215 insertions(+), 120 deletions(-)

M emulator/CMakeLists.txt
M emulator/test_kia.c
A emulator/virtual_kia.c
A emulator/virtual_kia.h
M emulator/CMakeLists.txt => emulator/CMakeLists.txt +1 -1
@@ 6,7 6,7 @@ include_directories(${SDL2_INCLUDE_DIRS})
add_executable(fbemu main.c)
target_link_libraries(fbemu lib65816a ${SDL2_LIBRARIES})

add_executable(test_kia test_kia.c)
add_executable(test_kia test_kia.c virtual_kia.c)
add_test(NAME test_kia COMMAND test_kia)

install(TARGETS fbemu)

M emulator/test_kia.c => emulator/test_kia.c +1 -119
@@ 4,125 4,7 @@
#include <string.h>
#include <stdbool.h>

/**
 * @brief The KIA queue depth.
 *
 * All hardware instances of the KIA implement a 16-byte queue.
 */
#define KIA_QUEUE_DEPTH 16

typedef struct {
  int     read_ptr;
  int     write_ptr;
  uint8_t queue[KIA_QUEUE_DEPTH];
} KIA_t;

/**
 * @brief Answers with the slot index after the one provided.
 */
int
next_slot(int slot) {
  return (slot + 1) % KIA_QUEUE_DEPTH;
}

/**
 * @brief Answers true if the queue is empty.
 */
bool
kia_is_empty(KIA_t *pk) {
  return (pk->read_ptr) == (pk->write_ptr);
}

/**
 * @brief Answers true if the queue is not empty.
 */
bool
kia_isnt_empty(KIA_t *pk) {
  return !kia_is_empty(pk);
}

/**
 * @brief Answers true if KIA queue is full.
 */
bool
kia_is_full(KIA_t *pk) {
  return next_slot(pk->write_ptr) == pk->read_ptr;
}

/**
 * @brief Answers true if KIA queue is not full.
 */
bool
kia_isnt_full(KIA_t *pk) {
  return !kia_is_full(pk);
}

/**
 * @brief Resets the KIA_t instance to its empty-queue condition.
 */
void
kia_reset(KIA_t *pk) {
  memset((void *)pk, 0, sizeof(KIA_t));
}

/**
 * @brief Answers with a new KIA instance.
 *
 * Answers NULL if there is no memory available.
 */
KIA_t *
kia_new(void) {
  KIA_t *pk = (KIA_t *)malloc(sizeof(KIA_t));
  if(pk) kia_reset(pk);
  return pk;
}

/**
 * @brief Answers with the queue's read/write pointers.
 *
 * Used for unit testing only.
 */
void
kia_test_get_pointers(
  KIA_t *pk, int *p_read_pointer, int *p_write_pointer
) {
  *p_read_pointer = pk->read_ptr;
  *p_write_pointer = pk->write_ptr;
}

/**
 * @brief Pops the input queue.
 */
void
kia_pop(KIA_t *pk) {
  if(kia_isnt_empty(pk)) pk->read_ptr = next_slot(pk->read_ptr);
}

/**
 * @brief Pushes the `byte` onto the tail of the input queue.
 *
 * If there isn't enough room, the byte will be dropped.
 */
void
kia_push(KIA_t *pk, uint8_t byte) {
  if(kia_isnt_full(pk)) {
    int wp = pk->write_ptr;
    pk->write_ptr = next_slot(wp);
    pk->queue[wp] = byte;
  }
}

/**
 * @brief Answers with the byte at the head of the queue.  Does NOT
 * pop the queue.
 *
 * Typically called by the emulator in response to the virtual CPU
 * reading from a memory-mapped I/O location.
 */
uint8_t
kia_peek(KIA_t *pk) {
  return pk->queue[pk->read_ptr];
}
#include "virtual_kia.h"

static int erc = 0;


A emulator/virtual_kia.c => emulator/virtual_kia.c +114 -0
@@ 0,0 1,114 @@
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>

#include "virtual_kia.h"

/**
 * @brief Answers with the slot index after the one provided.
 */
int
next_slot(int slot) {
  return (slot + 1) % KIA_QUEUE_DEPTH;
}

/**
 * @brief Answers true if the queue is empty.
 */
bool
kia_is_empty(KIA_t *pk) {
  return (pk->read_ptr) == (pk->write_ptr);
}

/**
 * @brief Answers true if the queue is not empty.
 */
bool
kia_isnt_empty(KIA_t *pk) {
  return !kia_is_empty(pk);
}

/**
 * @brief Answers true if KIA queue is full.
 */
bool
kia_is_full(KIA_t *pk) {
  return next_slot(pk->write_ptr) == pk->read_ptr;
}

/**
 * @brief Answers true if KIA queue is not full.
 */
bool
kia_isnt_full(KIA_t *pk) {
  return !kia_is_full(pk);
}

/**
 * @brief Resets the KIA_t instance to its empty-queue condition.
 */
void
kia_reset(KIA_t *pk) {
  memset((void *)pk, 0, sizeof(KIA_t));
}

/**
 * @brief Answers with a new KIA instance.
 *
 * Answers NULL if there is no memory available.
 */
KIA_t *
kia_new(void) {
  KIA_t *pk = (KIA_t *)malloc(sizeof(KIA_t));
  if(pk) kia_reset(pk);
  return pk;
}

/**
 * @brief Answers with the queue's read/write pointers.
 *
 * Used for unit testing only.
 */
void
kia_test_get_pointers(
  KIA_t *pk, int *p_read_pointer, int *p_write_pointer
) {
  *p_read_pointer = pk->read_ptr;
  *p_write_pointer = pk->write_ptr;
}

/**
 * @brief Pops the input queue.
 */
void
kia_pop(KIA_t *pk) {
  if(kia_isnt_empty(pk)) pk->read_ptr = next_slot(pk->read_ptr);
}

/**
 * @brief Pushes the `byte` onto the tail of the input queue.
 *
 * If there isn't enough room, the byte will be dropped.
 */
void
kia_push(KIA_t *pk, uint8_t byte) {
  if(kia_isnt_full(pk)) {
    int wp = pk->write_ptr;
    pk->write_ptr = next_slot(wp);
    pk->queue[wp] = byte;
  }
}

/**
 * @brief Answers with the byte at the head of the queue.  Does NOT
 * pop the queue.
 *
 * Typically called by the emulator in response to the virtual CPU
 * reading from a memory-mapped I/O location.
 */
uint8_t
kia_peek(KIA_t *pk) {
  return pk->queue[pk->read_ptr];
}


A emulator/virtual_kia.h => emulator/virtual_kia.h +99 -0
@@ 0,0 1,99 @@
#pragma once

#include <stdint.h>
#include <stdbool.h>

/**
 * @brief The KIA queue depth.
 *
 * All hardware instances of the KIA implement a 16-byte queue.
 */
#define KIA_QUEUE_DEPTH 16

/**
 * @brief This structure models the KIA core's state.
 */
typedef struct {
  int     read_ptr;
  int     write_ptr;
  uint8_t queue[KIA_QUEUE_DEPTH];
} KIA_t;

/**
 * @brief Answers with the slot index after the one provided.
 */
int
next_slot(int slot);

/**
 * @brief Answers true if the queue is empty.
 */
bool
kia_is_empty(KIA_t *pk);

/**
 * @brief Answers true if the queue is not empty.
 */
bool
kia_isnt_empty(KIA_t *pk);

/**
 * @brief Answers true if KIA queue is full.
 */
bool
kia_is_full(KIA_t *pk);

/**
 * @brief Answers true if KIA queue is not full.
 */
bool
kia_isnt_full(KIA_t *pk);

/**
 * @brief Resets the KIA_t instance to its empty-queue condition.
 */
void
kia_reset(KIA_t *pk);

/**
 * @brief Answers with a new KIA instance.
 *
 * Answers NULL if there is no memory available.
 */
KIA_t *
kia_new(void);

/**
 * @brief Answers with the queue's read/write pointers.
 *
 * Used for unit testing only.
 */
void
kia_test_get_pointers(
  KIA_t *pk, int *p_read_pointer, int *p_write_pointer
);

/**
 * @brief Pops the input queue.
 */
void
kia_pop(KIA_t *pk);

/**
 * @brief Pushes the `byte` onto the tail of the input queue.
 *
 * If there isn't enough room, the byte will be dropped.
 */
void
kia_push(KIA_t *pk, uint8_t byte);

/**
 * @brief Answers with the byte at the head of the queue.  Does NOT
 * pop the queue.
 *
 * Typically called by the emulator in response to the virtual CPU
 * reading from a memory-mapped I/O location.
 */
uint8_t
kia_peek(KIA_t *pk);