Добавлен: 16.03.2024
Просмотров: 50
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
Система команд Simple Computer
Получив текущую команду из оперативной памяти, устройство управления декодирует её с целью определить номер функции, которую надо выполнить и операнд. Формат команды следующий (см. рисунок 2): старший разряд содержит признак команды (0 – команда), разряды с 8 по 14 определяют код операции, младшие 7 разрядов содержат операнд.
Рисунок 2 – Формат команды центрального процессора Simple Computer
Выполнение команд центральным процессором Simple Computer
Команды выполняются последовательно. Адрес ячейки памяти, в которой находится текущая выполняемая команда, задается в регистре «Счетчик команд». Устройство управления запрашивает содержимое указанной ячейки памяти и декодирует его согласно используемому формату команд. Получив код операции, устройство управления определяет, является ли эта операция арифметикологической. Если да, то выполнение операции передается в АЛУ. В противном случае операция выполняется устройством управления. Процедура выполняется до тех пор, пока флаг «останов» не будет равен 1.
Консоль управления
Интерфейс консоли управления представлен на рисунке 1. Он содержит следующие области:
-
“Memory” – содержимое оперативной памяти Simple Computer. -
“Accumulator” – значение, находящееся в аккумуляторе; -
“instructionCounter” – значение регистра «счетчик команд»; -
“Operation” – результат декодирования операции; -
“Flags” – состояние регистра флагов («П» - переполнение при выполнении операции, «0» - ошибка деления на 0, «М» - ошибка выхода за границы памяти, «Т» - игнорированиетактовых импульсов, «Е» - указана неверная команда); -
“Cell” – значение выделенной ячейки памяти в области ―Memory‖ (используется для редактирования); -
“Keys” – подсказка по функциональным клавишам; -
“Input/Otput” – область, используемая Simple Computer в процессе выполнения программы для ввода информации с клавиатуры и вывода её на экран.
Содержимое ячеек памяти и регистров центрального процессора выводится в декодированном виде. При этом, знак «+» соответствует значению 0 в поле «признак команды», следующие две цифры – номер команды и затем операнд в шестнадцатеричной системе счисления.
Пользователь имеет возможность с помощью клавиш управления курсора выбирать ячейки оперативной памяти и задавать им значения. Нажав клавишу “F5”, пользователь может задать значение аккумулятору, “F6” – регистру «счетчик команд». Сохранить содержимое памяти (в бинарном виде) в файл или загрузить его обратно пользователь может, нажав на клавиши “l”, “s” соответственно (после нажатия в поле Input/Output пользователю предлагается ввести имя файла). Запустить программу на выполнение (установить значение флага «игнорировать такты таймера» в 0) можно с помощью клавиши “r”. В процессе выполнения программы, редактирование памяти и изменение значений регистров недоступно. Чтобы выполнить только текущую команду пользователь может нажать клавишу “t”. Обнулить содержимое памяти и задать регистрам значения «по умолчанию» можно нажав на клавишу “i”.
Блок-схемы
SimpleComputer
SimpleAssembler
SimpleBasic
Результаты проведенного исследования
Были получены знания о терминальных управляющих последовательностях, режимах работы терминала, псевдографике, а также принципах работы подсистемы прерываний ЭВМ.
В ходе курсовой работы были реализованы базовые команды УУ и АЛУ. Были написаны трансляторы: с Basic в Assembler; с Assembler в бинарный формат.
Примеры работы программы
Факториал числа SimpleBasic
Выполнение трансляции из SimpleBasic в SimpleAssembler
Факториал числа SimpleAssembler
Выполнение трансляции из SimpleAssembler в бинарный код
Компьютер после считывания из файла
Компьютер в момент работы
Вывод результата работы компьютера (результат в 16 СС)
Программа завершила свою работу
Приложение. Листинг
Makefile
d.PHONY: all clean run
COMPILER := g++
FLAGS := -fdiagnostics-color=always -Werror -MMD
SRC_SC := src/sc
BUILD_SC := build/sc
LIBS_SC := libs/sc
SRC_SA := src/sa
BUILD_SA := build/sa
SRC_SB := src/sb
BUILD_SB := build/sb
BIN := bin
SC := simpleComputer
SA := simpleAssembler
SB := simpleBasic
all: create $(BIN)/$(SC) $(BIN)/$(SA) $(BIN)/$(SB)
-include $((BUILD_SC)/*.d
-include $((BUILD_SA)/*.d
-include $((BUILD_SB)/*.d
sc: create $(BIN)/$(SC)
run_sc: sc
./$(BIN)/$(SC)
$(BIN)/$(SC): $(LIBS_SC)/libsimpleComputer.a $(LIBS_SC)/libmyTerm.a $(LIBS_SC)/libmyBigChars.a $(LIBS_SC)/libmyReadkey.a $(LIBS_SC)/libmyUI.a $(LIBS_SC)/libmyALU.a $(LIBS_SC)/libmyCU.a $(BUILD_SC)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SC) $(BUILD_SC)/main.o -L $(LIBS_SC) -lsimpleComputer -lmyUI -lmyTerm -lmyBigChars -lmyReadkey -lmyCU -lmyALU
$(BUILD_SC)/%.o: $(SRC_SC)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
$(LIBS_SC)/libsimpleComputer.a: $(BUILD_SC)/simpleComputer.o
ar cr $@ $^
$(LIBS_SC)/libmyTerm.a: $(BUILD_SC)/myTerm.o
ar cr $@ $^
$(LIBS_SC)/libmyBigChars.a: $(BUILD_SC)/myBigChars.o
ar cr $@ $^
$(LIBS_SC)/libmyReadkey.a: $(BUILD_SC)/myReadkey.o
ar cr $@ $^
$(LIBS_SC)/libmyUI.a: $(BUILD_SC)/myUI.o
ar cr $@ $^
$(LIBS_SC)/libmyALU.a: $(BUILD_SC)/myALU.o
ar cr $@ $^
$(LIBS_SC)/libmyCU.a: $(BUILD_SC)/myCU.o
ar cr $@ $^
sa: create $(BIN)/$(SA)
run_sa: create $(BIN)/$(SA)
./$(BIN)/$(SA)
$(BIN)/$(SA): $(BUILD_SA)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SA) $(BUILD_SA)/main.o
$(BUILD_SA)/%.o: $(SRC_SA)/%.cpps
$(COMPILER) $(FLAGS) -c $^ -o $@
sb: create $(BIN)/$(SB)
run_sb: create $(BIN)/$(SB)
./$(BIN)/$(SB)
$(BIN)/$(SB): $(BUILD_SB)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SB) $(BUILD_SB)/main.o
$(BUILD_SB)/%.o: $(SRC_SB)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
create:
mkdir -p $(BUILD_SC) $(BUILD_SA) $(BUILD_SB) $(LIBS_SC) $(BIN)
clean:
@rm -rf build libs $(BIN)
SimpleComputer
main.cpp
#include
#include "simpleComputer.hpp"
#include "myUI.hpp"
#include "myReadkey.hpp"
#include "myCU.hpp"
void signalHandler(int signal) ;
#include
int main(int argc, char const *argv[]){
ui_initial() ;
signal(SIGALRM, signalHandler) ;
signal(SIGUSR1, signalHandler) ;
bool zero, out, ignor, comm ;
keys key;
if (argc == 2){
sc_memoryLoad((char *)argv[1]) ;
}
else if (argc > 2){
ui_messageOutput((char *)"Exceeded the number of arguments", colors::RED) ;
return -1 ;
}
do {
sc_regGet(IGNORING_TACT_PULSES, &ignor);
ui_update() ;
rk_readKey(&key);
if (ignor){
sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
sc_regGet(OUT_OF_MEMORY, &out) ;
sc_regGet(INCORRECT_COMMAND, &comm) ;
if (zero || out || comm){
switch(key){
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
}
}
else{
switch(key){
case keys::KEY_UP:
ui_moveCurrMemPointer(keys::KEY_UP) ;
break ;
case keys::KEY_RIGHT:
ui_moveCurrMemPointer(keys::KEY_RIGHT) ;
break ;
case keys::KEY_DOWN:
ui_moveCurrMemPointer(keys::KEY_DOWN) ;
break ;
case keys::KEY_LEFT:
ui_moveCurrMemPointer(keys::KEY_LEFT) ;
break ;
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_R:
sc_regInit() ;
raise(SIGALRM) ;
break ;
case keys::KEY_T:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
CU() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
case keys::KEY_F5:
ui_setAccumulator() ;
break ;
case keys::KEY_F6:
ui_setICounter() ;
break ;
case keys::KEY_ENTER:
ui_setMCellValue() ;
break ;
}
}
}
else
if (key == keys::KEY_I)
raise(SIGUSR1) ;
} while(key != keys::KEY_ESC) ;
return 0 ;
}
void signalHandler(int signal){
switch (signal) {
case SIGALRM:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
if (CU()){
sc_regSet(IGNORING_TACT_PULSES, true);
ui_update() ;
alarm(0) ;
}
else
alarm(1) ;
rk_myTermRegime(false, 0, 0, false, false) ;
break ;
case SIGUSR1:
alarm(0) ;
ui_initial() ;
break ;
default:
break ;
}
}
simpleComputer.hpp
#ifndef SIMPLECOMPUTER_HPP
#define SIMPLECOMPUTER_HPP
#include
#define OVERFLOW 0 // Переполнение при выполнении операции
#define DIVISION_ERR_BY_ZERO 1 // Ошибка деления на 0
#define OUT_OF_MEMORY 2 // Ошибка выхода за границы памяти
#define IGNORING_TACT_PULSES 3 // Игнорирование тактовых импульсов
#define INCORRECT_COMMAND 4 // Указана неверная команда
const short int SC_REG_SIZE = 5 ;
const short int SC_MEM_SIZE = 100 ;
extern unsigned short int sc_accumulator ;
extern uint8_t sc_instructionCounter ;
int sc_memoryInit () ;
int sc_memorySet (unsigned short int address, unsigned short int value) ;
int sc_memoryGet (unsigned short int address, unsigned short int * value) ;
int sc_memorySave (char* filename) ;
int sc_memoryLoad (char* filename) ;
int sc_regInit () ;
int sc_regSet (int8_t reg, bool value) ;
int sc_regGet (int8_t reg, bool * value) ;
int sc_commandEncode (unsigned short int command, unsigned short int operand, unsigned short int * value) ;
int sc_commandDecode (unsigned short int value, unsigned short int * command, unsigned short int * operand) ;
#endif //SIMPLECOMPUTER_HPP
simpleComputer.cpp
#include "simpleComputer.hpp"
unsigned short int sc_memory[SC_MEM_SIZE] ;
uint8_t sc_regFLAGS ;
unsigned short int sc_accumulator ;
uint8_t sc_instructionCounter ;
/// Инициализирует оперативную память SC, задавая всем её ячейкам нулевые значения
/// \return 0
int sc_memoryInit()
{
sc_instructionCounter = 0 ;
for (unsigned short & mem : sc_memory)
mem = 0 ;
return 0 ;
}
/// Задает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySet(unsigned short int address, unsigned short int value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_memory[address] = value ;
return 0 ;
}
/// Возвращает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryGet(unsigned short int address, unsigned short int * value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
*value = sc_memory[address] ;
return 0 ;
}
/// Сохраняет содержимое памяти в файл в бинарном виде
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySave(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "wb"))){
return -1 ;
}
fwrite(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Загружает из указанного файла содержимое оперативной памяти
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryLoad(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "rb"))){
return -1 ;
}
fread(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Инициализирует регистр флагов нулевым значением
/// \return 0
int sc_regInit(){
sc_regFLAGS = 0 ;
return 0 ;
}
/// Устанавливает значение указанного регистра флагов
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regSet(int8_t reg, bool value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
value == 1 ? (sc_regFLAGS |= (1 << reg)) : (sc_regFLAGS &=
(1 << reg)) ;
return 0 ;
}
/// Возвращает значение указанного флага
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regGet(int8_t reg, bool *value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
*value = sc_regFLAGS & (1 << reg) ;
return 0 ;
}
/// Кодирует команду с указанным номером и операндом и помещает результат в value
/// \param command - команда
/// \param operand - операнд
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandEncode(unsigned short int command, unsigned short int operand, unsigned short int * value){
if (command > 0x7F)
return -1 ;
if (operand > 0x7F)
return -1 ;
* value = 0 ;
/* Операнд */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (operand >> i) & 1 ;
*value |= (bit << i) ;
}
/* Команда */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (command >> i) & 1 ;
*value |= (bit << (i + 7)) ;
}
return 0 ;
}
/// Декодирует значение как команду SС
/// \param value - значение
/// \param command - команда
/// \param operand - операнд
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandDecode(unsigned short int value, unsigned short int * command, unsigned short int * operand){
int tmpCom = 0, tmpOp = 0 ;
if ((value >> 14) & 1){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> i) & 1 ;
tmpOp |= (bit << i) ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> (i + 7)) & 1 ;
tmpCom |= (bit << i) ;
}
* command = tmpCom ;
* operand = tmpOp ;
return 0 ;
}
myTerm.hpp
#ifndef MYTERM_HPP
#define MYTERM_HPP
#include
#include
enum colors {
RED = 196,
PEACH = 203,
GREEN = 10,
SOFT_GREEN =192,
BLUE = 20,
BLACK = 16,
GRAY = 240,
WHITE = 15,
DEFAULT = 0};
int mt_clrScreen () ;
int mt_gotoXY(unsigned int col,unsigned int row) ;
int mt_getScreenSize(unsigned int *rows, unsigned int* cols) ;
int mt_setFGcolor(enum colors color) ;
int mt_setBGcolor(enum colors color) ;
int mt_setDefaultColorSettings() ;
#endif //MYTERM_HPP
myTerm.cpp
#include "myTerm.hpp"
/// Производит очистку и перемещение курсора в левый верхний угол экрана
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_clrScreen (){
printf("\033[H\033[2J") ;
return 0 ;
}
/// Перемещает курсор в указанную позицию
/// \param col - столбец
/// \param row - строка
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_gotoXY(unsigned int col, unsigned int row)
{
unsigned int rows, cols ;
if (mt_getScreenSize(&rows, &cols) == -1)
return -1 ;
if ((row > rows) || (row <= 0)||(col > cols) || (col <= 0))
return -1 ;
printf("\033[%d;%dH", row, col) ;
return 0 ;
}
/// Определяет размер экрана терминала
/// \param rows - кол-во строк
/// \param cols - кол-во столбцов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_getScreenSize(unsigned int *rows, unsigned int *cols){
winsize ws{} ;
if (ioctl(1, TIOCGWINSZ, &ws))
return -1 ;
* rows = ws.ws_row ;
* cols = ws.ws_col ;
return 0 ;
}
/// Устанавливает цвет последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setFGcolor(enum colors color){
printf("\033[38;5;%dm",color) ;
return 0 ;
}
/// Устанавливает цвет фона последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setBGcolor(enum colors color){
printf("\033[48;5;%dm",color) ;
return 0 ;
}
/// Возвращает цвета в стандартное состояние
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setDefaultColorSettings(){
printf("\033[0m") ;
return 0 ;
}
myUI.hpp
#ifndef MYUI_HPP
#define MYUI_HPP
#include
#include "myBigChars.hpp"
#include "myReadkey.hpp"
#include "simpleComputer.hpp"
int ui_initial() ;
int ui_update() ;
int setCurrMemPointer_to_ICounter() ;
int ui_moveCurrMemPointer(keys key) ;
int ui_setMCellValue() ;
int ui_saveMemory() ;
int ui_loadMemory() ;
int ui_setAccumulator() ;
int ui_setICounter() ;
bool checkCorrectInputHEX(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color);
int clearBuffIn() ;
#endif //MYUI_HPP
myUI.cpp
#include "myUI.hpp"
#include "myReadkey.hpp"
int8_t currMemCell = 0 ;
int drawingBoxes() ;
int drawingTexts() ;
int drawingMemory() ;
int drawingAccumulator() ;
int drawingInstructionCounter() ;
int drawingOperation() ;
int drawingFlags() ;
int drawingBigChar() ;
bool checkCorrectInputHEX(const char *buffer) ;
bool checkCorrectInputDEC(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color) ;
/// "Инициализация" интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_initial(){
currMemCell = 0 ;
if (rk_myTermSave())
return -1 ;
sc_memoryInit() ;
sc_accumulator &= (1 << 14) ;
sc_regInit() ;
sc_regSet(IGNORING_TACT_PULSES, true) ;
return 0 ;
}
/// Обновление интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_update(){
mt_clrScreen() ;
if (drawingBoxes())
return -1 ;
if (drawingTexts())
return -1 ;
if (drawingMemory())
return -1 ;
if (drawingAccumulator())
return -1 ;
if (drawingInstructionCounter())
return -1 ;
if (drawingOperation())
return -1 ;
if (drawingFlags())
return -1 ;
if (drawingBigChar())
return -1 ;
mt_gotoXY(1, 23) ;
printf("Input/Output:\n") ;
return 0 ;
}
/// Перемещение выделенной ячейки на значение ICounter
/// \return 0
int setCurrMemPointer_to_ICounter(){
currMemCell = sc_instructionCounter ;
return 0 ;
}
/// Перемещение выделенной ячейки
/// \param key - Клавиша
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_moveCurrMemPointer(keys key){
switch (key) {
case keys::KEY_UP: (currMemCell <= 9) ? (currMemCell = 90 + currMemCell) : (currMemCell -= 10) ; return 0 ;
case keys::KEY_RIGHT: (!((currMemCell + 1) % 10)) ? (currMemCell -= 9) : (currMemCell += 1) ; return 0 ;
case keys::KEY_DOWN: (currMemCell >= 90) ? (currMemCell = currMemCell - 90) : (currMemCell += 10) ; return 0 ;
case keys::KEY_LEFT: (!(currMemCell % 10)) ? (currMemCell += 9) : (currMemCell -= 1) ; return 0 ;
}
return -1 ;
}
int ui_setMCellValue(){
printf("Set the value of the cell under the number \033[38;5;%dm0x%02X\033[0m\n", colors::SOFT_GREEN, currMemCell) ;
printf("Enter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+')
i = 1 ;
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
if (sc_memorySet(currMemCell, res))
return -1 ;
return 0 ;
}
int ui_saveMemory(){
char filename[102] ;
printf("Saving file...\n") ;
printf("Enter the file name to save > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
printf("\033[38;5;%dmThe file name is too long. The length is trimmed to the first 100 characters.\033[0m\n", BLUE) ;
clearBuffIn(); // очистка потока ввода
}
else
filename[strlen(filename) - 1] = '\0' ;
if (sc_memorySave(filename)){
ui_messageOutput((char *)"Failed to save memory", colors::RED) ;
return -1 ;
}
else
ui_messageOutput((char *)"Successful save", colors::GREEN) ;
return 0 ;
}
int ui_loadMemory(){
char filename[102] ;
printf("Loading file...\n") ;
printf("Enter the file name to load > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
ui_messageOutput((char *)"The name of the file to open is too long (up to 100 characters are allowed)", colors::BLUE) ;
clearBuffIn(); // очистка потока ввода
return -1 ;
}
filename[strlen(filename) - 1] = '\0' ;
if (sc_memoryLoad(filename)){
ui_messageOutput((char *)"Failed to load memory", colors::RED) ;
return -1 ;
}
return 0 ;
}
int ui_setAccumulator(){
// может ли в accumulator храниться команда ? (теперь нет)
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"Accumulator\"\033[0m", colors::GREEN) ;
printf("\nEnter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+'){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if(number > 0x3FFF){
ui_messageOutput((char *)"The command value must not exceed 14 bits (0x3FFF)", colors::RED) ;
return -1 ;
}
else
{
number &= 0x3FFF ;
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
else{
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
}
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
sc_accumulator = res ;
return 0 ;
}
int ui_setICounter(){
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"InstructionCounter\"\033[0m between \033[38;5;%dm00\033[0m and \033[38;5;%dm99\033[0m inclusive\n", colors::GREEN, colors::SOFT_GREEN, colors::SOFT_GREEN) ;
printf("Enter value in \033[38;5;%dmDEC\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
if (!checkCorrectInputDEC(buffer)){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(buffer, &tmp, 10);
if(number > 99){
ui_messageOutput((char *)"The value must not exceed the amount of memory", colors::RED) ;
return -1 ;
}
sc_instructionCounter = (uint8_t)number ;
return 0 ;
}
/// Отрисовка "боксов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBoxes(){
if (bc_box(1, 1, 61, 12)) // Окно Memory
return -1 ;
if (bc_box(62, 1, 22, 3)) // Окно accumulator
return -1 ;
if (bc_box(62, 4, 22, 3)) // Окно instructionCounter
return -1 ;
if (bc_box(62, 7, 22, 3)) // Окно Operation
return -1 ;
if (bc_box(62, 10, 22, 3)) // Окно Flags
return -1 ;
if (bc_box(1, 13, 52, 10)) // Окно BigChars
return -1 ;
if (bc_box(53, 13, 31, 10)) // Окно Keys
return -1 ;
return 0 ;
}
/// Отрисовка заголовков и текста
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingTexts(){
/* Заголовки */
mt_gotoXY(30,1) ;
printf(" Memory ") ;
mt_gotoXY(66,1) ;
printf(" accumulator ") ;
mt_gotoXY(63,4) ;
printf(" instructionCounter ") ;
mt_gotoXY(67,7) ;
printf(" Operation ") ;
mt_gotoXY(69,10) ;
printf(" Flags ") ;
mt_gotoXY(54,13) ;
printf(" Keys: ") ;
/* HotKeys */
char* hotK[] = {(char *)"l - load",
(char *)"s - save",
(char *)"r - run",
(char *)"t - step",
(char *)"i - reset",
(char *)"F5 - accumulator",
(char *)"F6 - instructionCounter"};
for (int i = 0 ; i < sizeof(hotK) / sizeof(*hotK) ; ++i) {
mt_gotoXY(54,i + 14) ;
printf("%s", hotK[i]) ;
}
return 0 ;
}
/// Отрисовка памяти
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingMemory(){
for (int i = 0 ; i < 10 ; ++i)
for (int j = 0 ; j < 10 ; ++j) {
mt_gotoXY(2 + (5 * j + j), 2 + i) ;
unsigned short int tmp ;
sc_memoryGet(i * 10 + j, &tmp) ;
if ((i * 10 + j) == currMemCell)
mt_setBGcolor(colors::GREEN) ;
if((tmp >> 14) & 1)
if((tmp >> 13) & 1)
printf("-%04X", (
(tmp - 1)) & 0x3FFF) ;
else
printf(" %04X", tmp & 0x1FFF) ;
else
printf("+%04X", tmp) ;
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка accumulator
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingAccumulator(){
mt_gotoXY(70,2) ;
// bool over ;
// sc_regGet(OVERFLOW, &over) ;
// if (over){
// mt_setFGcolor(colors::PEACH) ;
// printf(" over") ;
// mt_setDefaultColorSettings() ;
// }
// else{
if((sc_accumulator >> 14) & 1)
if((sc_accumulator >> 13) & 1)
printf("-%04X", (
(sc_accumulator - 1)) & 0x3FFF) ;
else
printf(" %04X", sc_accumulator & 0x1FFF) ;
else
printf("+%04X", sc_accumulator) ;
// }
return 0 ;
}
/// Отрисовка Operation
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingOperation(){
mt_gotoXY(69,8) ;
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1)){
unsigned short int operand, command ;
sc_commandDecode(tmp, &command, &operand) ;
printf("+%02X:%02X", command, operand) ;
}
else{
unsigned short int left, right ;
bool negative = (tmp >> 13) & 1 ;
if(negative)
tmp = (
(tmp - 1)) & 0x3FFF ;
else
tmp &= 0x1FFF ;
left = tmp >> 8 ;
right = tmp & 0xFF ;
negative ? printf("-%02X:%02X", left, right) : printf(" %02X:%02X", left, right) ;
}
return 0 ;
}
/// Отрисовка instructionCounter
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingInstructionCounter(){
mt_gotoXY(71,5) ;
// bool over, zero, out, comm ;
// sc_regGet(OVERFLOW, &over) ;
// sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
// sc_regGet(OUT_OF_MEMORY, &out) ;
// sc_regGet(INCORRECT_COMMAND, &comm) ;
// mt_gotoXY(71,5) ;
// if (over || zero || out || comm){
// mt_setFGcolor(colors::SOFT_GREEN) ;
// printf("null") ;
// mt_setDefaultColorSettings() ;
// }
// else
printf("%04X", sc_instructionCounter) ;
return 0 ;
}
/// Отрисовка флагов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingFlags(){
char tmp[] = {'O', 'Z', 'M', 'I', 'C'};
for (int i = 0 ; i < SC_REG_SIZE ; ++i) {
bool value ;
if (sc_regGet(i, &value))
return -1 ;
mt_gotoXY(68 + (i * 2), 11) ;
if (value){
mt_setFGcolor(colors::PEACH) ;
printf("%c", tmp[i]) ;
}
else{
mt_setFGcolor(colors::GRAY) ;
printf("%c", tmp[i]) ;
}
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка "BigChar'ов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBigChar(){
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1))
bc_printBigChar(bc[16], 2, 14, GREEN) ;
else if((tmp >> 13) & 1){
bc_printBigChar(bc[17], 2, 14, GREEN) ;
tmp = (
(tmp - 1)) & 0x3FFF;
}
else
tmp &= 0x3FFF ;
for (int i = 0; i < 4; ++i) {
int ch = (tmp & ( 0xF << (4 * (3 - i)) )) >> (4 * (3 - i)) ;
bc_printBigChar(bc[ch], 2 + 8 * (i + 1) + 2 * (i + 1), 14, GREEN) ;
}
return 0 ;
}
bool checkCorrectInputHEX(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 4)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isxdigit(buffer[i])))
return false ;
return true ;
}
bool checkCorrectInputDEC(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 5)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isdigit(buffer[i])))
return false ;
return true ;
}
int ui_messageOutput(char *str, enum colors color){
printf("\033[38;5;%dm%s\033[0m", color, str) ;
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
return 0 ;
}
int clearBuffIn(){
int c;
do {
c = getchar();
} while (c != '\n' && c != '\0');
return 0 ;
}
myReadkey.hpp
#ifndef MYREADKEY_HPP
#define MYREADKEY_HPP
#include
#include
#include
extern termios save;
enum keys
{
KEY_L,
KEY_S,
KEY_R,
KEY_T,
KEY_I,
KEY_F5,
KEY_F6 ,
KEY_UP,
KEY_DOWN,
KEY_RIGHT,
KEY_LEFT,
KEY_ESC,
KEY_ENTER,
KEY_OTHER,
};
int rk_readKey(enum keys *key) ;
int rk_myTermSave() ;
int rk_myTermRestore() ;
int rk_myTermRegime (bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint) ;
#endif //MYREADKEY_HPP
myReadkey.cpp
#include "myReadkey.hpp"
termios save;
/// Возвращающую первую клавишу, которую нажал пользователь
/// \param key - Адрес переменной, в которую возвращается номер нажатой клавиши
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_readKey (enum keys * key){
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
rk_myTermRestore() ;
if (buffer[0] == '\033')
if (buffer[1] == '\0')
*key = KEY_ESC ;
else if (buffer[1] == '[')
if (buffer[2] == 'A' and buffer[3] == '\0')
*key = KEY_UP ;
else if (buffer[2] == 'B' and buffer[3] == '\0')
*key = KEY_DOWN ;
else if (buffer[2] == 'C' and buffer[3] == '\0')
*key = KEY_RIGHT ;
else if (buffer[2] == 'D' and buffer[3] == '\0')
*key = KEY_LEFT ;
else if (buffer[2] == '1' and buffer[3] == '5')
*key = KEY_F5 ;
else if (buffer[2] == '1' and buffer[3] == '7')
*key = KEY_F6 ;
else
*key = KEY_OTHER ;
else
*key = KEY_OTHER ;
else if (buffer[0] == '\n' and buffer[1] == '\0')
*key = KEY_ENTER ;
else
if ((buffer[0] == 'l' or buffer[0] == 'L') and buffer[1] == '\0')
*key = KEY_L ;
else if ((buffer[0] == 's' or buffer[0] == 'S') and buffer[1] == '\0')
*key = KEY_S ;
else if ((buffer[0] == 'r' or buffer[0] == 'R') and buffer[1] == '\0')
*key = KEY_R ;
else if ((buffer[0] == 't' or buffer[0] == 'T') and buffer[1] == '\0')
*key = KEY_T ;
else if ((buffer[0] == 'i' or buffer[0] == 'I') and buffer[1] == '\0')
*key = KEY_I ;
else
*key = KEY_OTHER ;
return 0 ;
}
/// Функция, сохраняющая текущие параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermSave(){
if (tcgetattr(fileno(stdin), &save))
return -1 ;
return 0 ;
}
/// Функция, восстанавливающая сохраненные параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRestore(){
tcsetattr(fileno(stdin), TCSAFLUSH, &save) ;
return 0 ;
}
/// Функция, переключающая режим работы терминала (канонический / неканонический)
/// \param regime
/// \param vtime
/// \param vmin
/// \param echo
/// \param sigint
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRegime(bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint){
termios curr{} ;
tcgetattr(fileno(stdin), &curr) ;
if(regime)
curr.c_lflag |= ICANON ;
else{
curr.c_lflag &=
ICANON ;
sigint ? (curr.c_lflag |= ISIG) : (curr.c_lflag &=
ISIG) ;
echo ? (curr.c_lflag |= ECHO) : (curr.c_lflag &=
ECHO) ;
curr.c_cc[VMIN] = vmin ;
curr.c_cc[VTIME] = vtime ;
}
tcsetattr(0,TCSAFLUSH,&curr) ;
return 0 ;
}
commands.hpp
#ifndef COMMANDS_HPP
#define COMMANDS_HPP
#define READ 0x10
#define WRITE 0x11
#define LOAD 0x20
#define STORE 0x21
#define ADD 0x30
#define SUB 0x31
#define DIVIDE 0x32
#define MUL 0x33
#define JUMP 0x40
#define JNEG 0x41
#define JZ 0x42
#define HALT 0x43
#define RCR 0x63
#endif //COMMANDS_HPP
myCU.hpp
#ifndef CU_HPP
#define CU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
#include "myALU.hpp"
int CU() ;
#endif //CU_HPP
myCU.cpp
#include "myCU.hpp"
int cu_read(unsigned short int operand) ;
int cu_write(unsigned short int operand) ;
int cu_load(unsigned short int operand) ;
int cu_store(unsigned short int operand) ;
int cu_jump(unsigned short int operand) ;
int cu_jneg(unsigned short int operand) ;
int cu_jz(unsigned short int operand) ;
int CU (){
unsigned short int command = 0;
unsigned short int operand = 0;
unsigned short int currCell;
sc_memoryGet(sc_instructionCounter, &currCell) ;
if (sc_commandDecode(currCell, &command, &operand)){
return -1 ;
}
switch (command) {
case READ:
if (cu_read(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case WRITE:
if (cu_write(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case LOAD :
if (cu_load(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case STORE :
if (cu_store(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case JUMP :
if (cu_jump(operand))
return -1 ;
break ;
case JNEG :
if (cu_jneg(operand))
return -1 ;
break ;
case JZ :
if (cu_jz(operand))
return -1 ;
break ;
case HALT :
return -1 ;
break ;
default:
if (ALU(command, operand))
return -1 ;
break ;
}
return 0 ;
}
int cu_read(unsigned short int operand){
rk_myTermRestore() ;
printf("Enter value of cell[\033[38;5;%dm0x%02X\033[0m] in \033[38;5;%dmHEX\033[0m format > ", colors::SOFT_GREEN, operand, colors::PEACH) ;
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
rk_myTermRegime(false, 0, 0, false, false) ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+' or buffer[0] == '-')
i = 1 ;
else{
res |= (1 << 14) ;
(buffer[0] == '-') ? (res |= (1 << 13)) : i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
res |= (1 << 15) ;
}
else{
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if (number > 0x3FFF)
res |= (1 << 15) ;
else
{
number &= 0x3FFF ;
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value)){
res |= (1 << 15) ;
}
else
res |= value ;
}
}
else{
if (number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
res |= (1 << 15) ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
}
if (sc_memorySet(operand, (unsigned short int)res))
return -1 ;
return 0 ;
}
int cu_write(unsigned short int operand){
unsigned short int value;
if(sc_memoryGet(operand, &value)){
return -1 ;
}
printf("Value in a cell [\033[38;5;%dm0x%02X\033[0m] < ", colors::SOFT_GREEN, operand) ;
if ((value >> 14) & 1)
if ((value >> 13) & 1)
printf("-%04X", (
(value - 1)) & 0x3FFF) ;
else
printf(" %04X", value & 0x1FFF) ;
else
printf("+%04X", value) ;
getchar() ;
return 0 ;
}
int cu_load(unsigned short int operand){
unsigned short int value;
if (sc_memoryGet(operand, &value)){
return -1 ;
}
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return - 1;
}
sc_accumulator = value ;
return 0 ;
}
int cu_store(unsigned short int operand){
if (sc_memorySet(operand, sc_accumulator))
return -1 ;
return 0 ;
}
int cu_jump(unsigned short int operand){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
return 0 ;
}
int cu_jneg(unsigned short int operand){
if (((sc_accumulator >> 14) & 1) and ((sc_accumulator >> 13) & 1)){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
}
else
sc_instructionCounter++ ;
return 0 ;
}
int cu_jz(unsigned short int operand){
if (((sc_accumulator >> 14) & 1) and ((sc_accumulator & 0x3FFF) == 0)){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
}
else
sc_instructionCounter++ ;
return 0 ;
}
myALU.hpp
#ifndef MYALU_HPP
#define MYALU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
int ALU(unsigned short int command, unsigned short int operand) ;
#endif //MYALU_HPP
myALU.cpp
#include "myALU.hpp"
int alu_add(unsigned short int value) ;
int alu_divide(unsigned short int operand) ;
int alu_mul(unsigned short int operand) ;
int alu_rcr(unsigned short int operand) ;
int ALU(unsigned short int command, unsigned short int operand){
unsigned short int value ;
switch (command) {
case ADD:
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
if (alu_add(value))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case SUB:
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
if ((value >> 13) & 1) // Отрицательное
value =
((value & 0x3FFF) - 1) ;
else
value = (
(value & 0x3FFF)) + 1 ;
value &= 0x3FFF ;
value |= (1 << 14) ;
if (alu_add(value))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case DIVIDE:
if (alu_divide(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case MUL:
if (alu_mul(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case RCR:
if (alu_rcr(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
default:
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
return 0 ;
}
int alu_add(unsigned short int value){
unsigned short int accumulator, res;
accumulator = sc_accumulator & 0x3FFF ;
value &= 0x3FFF;
if (((accumulator >> 13) & 1) and ((value >> 13) & 1)){ // Если оба отрицательны
value =
(value - 1) & 0x3FFF ;
accumulator =
(accumulator - 1) & 0x3FFF ;
res = accumulator + value;
if (res > 0x2000){
sc_regSet(OVERFLOW, true) ;
}
res =
res + 1 ;
}
else if (((accumulator >> 13) & 1) or ((value >> 13) & 1)) { // Если одно из чисел отрицательно
res = accumulator + value ;
}
else{
res = accumulator + value ;
if (res > 0x1FFF){
sc_regSet(OVERFLOW, true) ;
}
}
res |= (1 << 14) ;
sc_accumulator = res ;
return 0 ;
}
int alu_divide(unsigned short int operand){
unsigned short int value,accumulator, res ;
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
bool negative = 0 ;
accumulator = sc_accumulator & 0x3FFF ;
value &= 0x3FFF;
if ((accumulator >> 13) & 1){
negative = !negative ;
accumulator =
(accumulator - 1);
}
accumulator &= 0x3FFF ;
if ((value >> 13) & 1){
negative = !negative ;
value =
(value - 1);
}
value &= 0x3FFF ;
if (value == 0){
sc_regSet(DIVISION_ERR_BY_ZERO, true) ;
return -1 ;
}
res = accumulator / value ;
if (negative){
if (res > 0x2000){
sc_regSet(OVERFLOW, true) ;
}
res = (
res + 1) & 0x3FFF ;
res |= (1 << 14) ;
sc_accumulator = res ;
}
else {
if (res > 0x1FFF){
sc_regSet(OVERFLOW, true) ;
}
res |= (1 << 14) ;
sc_accumulator = res ;
}
return 0 ;
}
int alu_mul(unsigned short int operand){
unsigned short int value,accumulator, res ;
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
bool negative = 0 ;
accumulator = sc_accumulator & 0x3FFF ;
value &= 0x3FFF;
if ((accumulator >> 13) & 1){
negative = !negative ;
accumulator =
(accumulator - 1);
}
accumulator &= 0x1FFF ;
if ((value >> 13) & 1){
negative = !negative ;
value =
(value - 1);
}
value &= 0x1FFF ;
res = accumulator * value ;
if (negative){
if (res > 0x2000){
sc_regSet(OVERFLOW, true) ;
}
res = (
res + 1) & 0x3FFF ;
res |= (1 << 14) ;
sc_accumulator = res ;
}
else {
if (res > 0x1FFF){
sc_regSet(OVERFLOW, true) ;
}
res |= (1 << 14) ;
sc_accumulator = res ;
}
return 0 ;
}
int alu_rcr(unsigned short int operand){
unsigned short int res, value ;
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
bool negative = (value >> 13) & 1;
if (negative) // Отрицательное
value =
(value - 1) & 0x3FFF ;
else
value &= 0x1FFF ;
res = (value>> 1) | ((value & 1) << 12) ;
if (negative){
if (res > 0x2000)
sc_regSet(OVERFLOW, true) ;
res = (
res + 1) & 0x3FFF ;
Приложение. Листинг
Makefile
d.PHONY: all clean run
COMPILER := g++
FLAGS := -fdiagnostics-color=always -Werror -MMD
SRC_SC := src/sc
BUILD_SC := build/sc
LIBS_SC := libs/sc
SRC_SA := src/sa
BUILD_SA := build/sa
SRC_SB := src/sb
BUILD_SB := build/sb
BIN := bin
SC := simpleComputer
SA := simpleAssembler
SB := simpleBasic
all: create $(BIN)/$(SC) $(BIN)/$(SA) $(BIN)/$(SB)
-include $((BUILD_SC)/*.d
-include $((BUILD_SA)/*.d
-include $((BUILD_SB)/*.d
sc: create $(BIN)/$(SC)
run_sc: sc
./$(BIN)/$(SC)
$(BIN)/$(SC): $(LIBS_SC)/libsimpleComputer.a $(LIBS_SC)/libmyTerm.a $(LIBS_SC)/libmyBigChars.a $(LIBS_SC)/libmyReadkey.a $(LIBS_SC)/libmyUI.a $(LIBS_SC)/libmyALU.a $(LIBS_SC)/libmyCU.a $(BUILD_SC)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SC) $(BUILD_SC)/main.o -L $(LIBS_SC) -lsimpleComputer -lmyUI -lmyTerm -lmyBigChars -lmyReadkey -lmyCU -lmyALU
$(BUILD_SC)/%.o: $(SRC_SC)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
$(LIBS_SC)/libsimpleComputer.a: $(BUILD_SC)/simpleComputer.o
ar cr $@ $^
$(LIBS_SC)/libmyTerm.a: $(BUILD_SC)/myTerm.o
ar cr $@ $^
$(LIBS_SC)/libmyBigChars.a: $(BUILD_SC)/myBigChars.o
ar cr $@ $^
$(LIBS_SC)/libmyReadkey.a: $(BUILD_SC)/myReadkey.o
ar cr $@ $^
$(LIBS_SC)/libmyUI.a: $(BUILD_SC)/myUI.o
ar cr $@ $^
$(LIBS_SC)/libmyALU.a: $(BUILD_SC)/myALU.o
ar cr $@ $^
$(LIBS_SC)/libmyCU.a: $(BUILD_SC)/myCU.o
ar cr $@ $^
sa: create $(BIN)/$(SA)
run_sa: create $(BIN)/$(SA)
./$(BIN)/$(SA)
$(BIN)/$(SA): $(BUILD_SA)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SA) $(BUILD_SA)/main.o
$(BUILD_SA)/%.o: $(SRC_SA)/%.cpps
$(COMPILER) $(FLAGS) -c $^ -o $@
sb: create $(BIN)/$(SB)
run_sb: create $(BIN)/$(SB)
./$(BIN)/$(SB)
$(BIN)/$(SB): $(BUILD_SB)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SB) $(BUILD_SB)/main.o
$(BUILD_SB)/%.o: $(SRC_SB)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
create:
mkdir -p $(BUILD_SC) $(BUILD_SA) $(BUILD_SB) $(LIBS_SC) $(BIN)
clean:
@rm -rf build libs $(BIN)
SimpleComputer
main.cpp
#include
#include "simpleComputer.hpp"
#include "myUI.hpp"
#include "myReadkey.hpp"
#include "myCU.hpp"
void signalHandler(int signal) ;
#include
int main(int argc, char const *argv[]){
ui_initial() ;
signal(SIGALRM, signalHandler) ;
signal(SIGUSR1, signalHandler) ;
bool zero, out, ignor, comm ;
keys key;
if (argc == 2){
sc_memoryLoad((char *)argv[1]) ;
}
else if (argc > 2){
ui_messageOutput((char *)"Exceeded the number of arguments", colors::RED) ;
return -1 ;
}
do {
sc_regGet(IGNORING_TACT_PULSES, &ignor);
ui_update() ;
rk_readKey(&key);
if (ignor){
sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
sc_regGet(OUT_OF_MEMORY, &out) ;
sc_regGet(INCORRECT_COMMAND, &comm) ;
if (zero || out || comm){
switch(key){
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
}
}
else{
switch(key){
case keys::KEY_UP:
ui_moveCurrMemPointer(keys::KEY_UP) ;
break ;
case keys::KEY_RIGHT:
ui_moveCurrMemPointer(keys::KEY_RIGHT) ;
break ;
case keys::KEY_DOWN:
ui_moveCurrMemPointer(keys::KEY_DOWN) ;
break ;
case keys::KEY_LEFT:
ui_moveCurrMemPointer(keys::KEY_LEFT) ;
break ;
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_R:
sc_regInit() ;
raise(SIGALRM) ;
break ;
case keys::KEY_T:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
CU() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
case keys::KEY_F5:
ui_setAccumulator() ;
break ;
case keys::KEY_F6:
ui_setICounter() ;
break ;
case keys::KEY_ENTER:
ui_setMCellValue() ;
break ;
}
}
}
else
if (key == keys::KEY_I)
raise(SIGUSR1) ;
} while(key != keys::KEY_ESC) ;
return 0 ;
}
void signalHandler(int signal){
switch (signal) {
case SIGALRM:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
if (CU()){
sc_regSet(IGNORING_TACT_PULSES, true);
ui_update() ;
alarm(0) ;
}
else
alarm(1) ;
rk_myTermRegime(false, 0, 0, false, false) ;
break ;
case SIGUSR1:
alarm(0) ;
ui_initial() ;
break ;
default:
break ;
}
}
simpleComputer.hpp
#ifndef SIMPLECOMPUTER_HPP
#define SIMPLECOMPUTER_HPP
#include
#define OVERFLOW 0 // Переполнение при выполнении операции
#define DIVISION_ERR_BY_ZERO 1 // Ошибка деления на 0
#define OUT_OF_MEMORY 2 // Ошибка выхода за границы памяти
#define IGNORING_TACT_PULSES 3 // Игнорирование тактовых импульсов
#define INCORRECT_COMMAND 4 // Указана неверная команда
const short int SC_REG_SIZE = 5 ;
const short int SC_MEM_SIZE = 100 ;
extern unsigned short int sc_accumulator ;
extern uint8_t sc_instructionCounter ;
int sc_memoryInit () ;
int sc_memorySet (unsigned short int address, unsigned short int value) ;
int sc_memoryGet (unsigned short int address, unsigned short int * value) ;
int sc_memorySave (char* filename) ;
int sc_memoryLoad (char* filename) ;
int sc_regInit () ;
int sc_regSet (int8_t reg, bool value) ;
int sc_regGet (int8_t reg, bool * value) ;
int sc_commandEncode (unsigned short int command, unsigned short int operand, unsigned short int * value) ;
int sc_commandDecode (unsigned short int value, unsigned short int * command, unsigned short int * operand) ;
#endif //SIMPLECOMPUTER_HPP
simpleComputer.cpp
#include "simpleComputer.hpp"
unsigned short int sc_memory[SC_MEM_SIZE] ;
uint8_t sc_regFLAGS ;
unsigned short int sc_accumulator ;
uint8_t sc_instructionCounter ;
/// Инициализирует оперативную память SC, задавая всем её ячейкам нулевые значения
/// \return 0
int sc_memoryInit()
{
sc_instructionCounter = 0 ;
for (unsigned short & mem : sc_memory)
mem = 0 ;
return 0 ;
}
/// Задает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySet(unsigned short int address, unsigned short int value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_memory[address] = value ;
return 0 ;
}
/// Возвращает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryGet(unsigned short int address, unsigned short int * value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
*value = sc_memory[address] ;
return 0 ;
}
/// Сохраняет содержимое памяти в файл в бинарном виде
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySave(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "wb"))){
return -1 ;
}
fwrite(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Загружает из указанного файла содержимое оперативной памяти
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryLoad(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "rb"))){
return -1 ;
}
fread(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Инициализирует регистр флагов нулевым значением
/// \return 0
int sc_regInit(){
sc_regFLAGS = 0 ;
return 0 ;
}
/// Устанавливает значение указанного регистра флагов
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regSet(int8_t reg, bool value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
value == 1 ? (sc_regFLAGS |= (1 << reg)) : (sc_regFLAGS &=
(1 << reg)) ;
return 0 ;
}
/// Возвращает значение указанного флага
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regGet(int8_t reg, bool *value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
*value = sc_regFLAGS & (1 << reg) ;
return 0 ;
}
/// Кодирует команду с указанным номером и операндом и помещает результат в value
/// \param command - команда
/// \param operand - операнд
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandEncode(unsigned short int command, unsigned short int operand, unsigned short int * value){
if (command > 0x7F)
return -1 ;
if (operand > 0x7F)
return -1 ;
* value = 0 ;
/* Операнд */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (operand >> i) & 1 ;
*value |= (bit << i) ;
}
/* Команда */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (command >> i) & 1 ;
*value |= (bit << (i + 7)) ;
}
return 0 ;
}
/// Декодирует значение как команду SС
/// \param value - значение
/// \param command - команда
/// \param operand - операнд
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandDecode(unsigned short int value, unsigned short int * command, unsigned short int * operand){
int tmpCom = 0, tmpOp = 0 ;
if ((value >> 14) & 1){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> i) & 1 ;
tmpOp |= (bit << i) ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> (i + 7)) & 1 ;
tmpCom |= (bit << i) ;
}
* command = tmpCom ;
* operand = tmpOp ;
return 0 ;
}
myTerm.hpp
#ifndef MYTERM_HPP
#define MYTERM_HPP
#include
#include
enum colors {
RED = 196,
PEACH = 203,
GREEN = 10,
SOFT_GREEN =192,
BLUE = 20,
BLACK = 16,
GRAY = 240,
WHITE = 15,
DEFAULT = 0};
int mt_clrScreen () ;
int mt_gotoXY(unsigned int col,unsigned int row) ;
int mt_getScreenSize(unsigned int *rows, unsigned int* cols) ;
int mt_setFGcolor(enum colors color) ;
int mt_setBGcolor(enum colors color) ;
int mt_setDefaultColorSettings() ;
#endif //MYTERM_HPP
myTerm.cpp
#include "myTerm.hpp"
/// Производит очистку и перемещение курсора в левый верхний угол экрана
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_clrScreen (){
printf("\033[H\033[2J") ;
return 0 ;
}
/// Перемещает курсор в указанную позицию
/// \param col - столбец
/// \param row - строка
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_gotoXY(unsigned int col, unsigned int row)
{
unsigned int rows, cols ;
if (mt_getScreenSize(&rows, &cols) == -1)
return -1 ;
if ((row > rows) || (row <= 0)||(col > cols) || (col <= 0))
return -1 ;
printf("\033[%d;%dH", row, col) ;
return 0 ;
}
/// Определяет размер экрана терминала
/// \param rows - кол-во строк
/// \param cols - кол-во столбцов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_getScreenSize(unsigned int *rows, unsigned int *cols){
winsize ws{} ;
if (ioctl(1, TIOCGWINSZ, &ws))
return -1 ;
* rows = ws.ws_row ;
* cols = ws.ws_col ;
return 0 ;
}
/// Устанавливает цвет последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setFGcolor(enum colors color){
printf("\033[38;5;%dm",color) ;
return 0 ;
}
/// Устанавливает цвет фона последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setBGcolor(enum colors color){
printf("\033[48;5;%dm",color) ;
return 0 ;
}
/// Возвращает цвета в стандартное состояние
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setDefaultColorSettings(){
printf("\033[0m") ;
return 0 ;
}
myUI.hpp
#ifndef MYUI_HPP
#define MYUI_HPP
#include
#include "myBigChars.hpp"
#include "myReadkey.hpp"
#include "simpleComputer.hpp"
int ui_initial() ;
int ui_update() ;
int setCurrMemPointer_to_ICounter() ;
int ui_moveCurrMemPointer(keys key) ;
int ui_setMCellValue() ;
int ui_saveMemory() ;
int ui_loadMemory() ;
int ui_setAccumulator() ;
int ui_setICounter() ;
bool checkCorrectInputHEX(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color);
int clearBuffIn() ;
#endif //MYUI_HPP
myUI.cpp
#include "myUI.hpp"
#include "myReadkey.hpp"
int8_t currMemCell = 0 ;
int drawingBoxes() ;
int drawingTexts() ;
int drawingMemory() ;
int drawingAccumulator() ;
int drawingInstructionCounter() ;
int drawingOperation() ;
int drawingFlags() ;
int drawingBigChar() ;
bool checkCorrectInputHEX(const char *buffer) ;
bool checkCorrectInputDEC(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color) ;
/// "Инициализация" интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_initial(){
currMemCell = 0 ;
if (rk_myTermSave())
return -1 ;
sc_memoryInit() ;
sc_accumulator &= (1 << 14) ;
sc_regInit() ;
sc_regSet(IGNORING_TACT_PULSES, true) ;
return 0 ;
}
/// Обновление интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_update(){
mt_clrScreen() ;
if (drawingBoxes())
return -1 ;
if (drawingTexts())
return -1 ;
if (drawingMemory())
return -1 ;
if (drawingAccumulator())
return -1 ;
if (drawingInstructionCounter())
return -1 ;
if (drawingOperation())
return -1 ;
if (drawingFlags())
return -1 ;
if (drawingBigChar())
return -1 ;
mt_gotoXY(1, 23) ;
printf("Input/Output:\n") ;
return 0 ;
}
/// Перемещение выделенной ячейки на значение ICounter
/// \return 0
int setCurrMemPointer_to_ICounter(){
currMemCell = sc_instructionCounter ;
return 0 ;
}
/// Перемещение выделенной ячейки
/// \param key - Клавиша
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_moveCurrMemPointer(keys key){
switch (key) {
case keys::KEY_UP: (currMemCell <= 9) ? (currMemCell = 90 + currMemCell) : (currMemCell -= 10) ; return 0 ;
case keys::KEY_RIGHT: (!((currMemCell + 1) % 10)) ? (currMemCell -= 9) : (currMemCell += 1) ; return 0 ;
case keys::KEY_DOWN: (currMemCell >= 90) ? (currMemCell = currMemCell - 90) : (currMemCell += 10) ; return 0 ;
case keys::KEY_LEFT: (!(currMemCell % 10)) ? (currMemCell += 9) : (currMemCell -= 1) ; return 0 ;
}
return -1 ;
}
int ui_setMCellValue(){
printf("Set the value of the cell under the number \033[38;5;%dm0x%02X\033[0m\n", colors::SOFT_GREEN, currMemCell) ;
printf("Enter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+')
i = 1 ;
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
if (sc_memorySet(currMemCell, res))
return -1 ;
return 0 ;
}
int ui_saveMemory(){
char filename[102] ;
printf("Saving file...\n") ;
printf("Enter the file name to save > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
printf("\033[38;5;%dmThe file name is too long. The length is trimmed to the first 100 characters.\033[0m\n", BLUE) ;
clearBuffIn(); // очистка потока ввода
}
else
filename[strlen(filename) - 1] = '\0' ;
if (sc_memorySave(filename)){
ui_messageOutput((char *)"Failed to save memory", colors::RED) ;
return -1 ;
}
else
ui_messageOutput((char *)"Successful save", colors::GREEN) ;
return 0 ;
}
int ui_loadMemory(){
char filename[102] ;
printf("Loading file...\n") ;
printf("Enter the file name to load > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
ui_messageOutput((char *)"The name of the file to open is too long (up to 100 characters are allowed)", colors::BLUE) ;
clearBuffIn(); // очистка потока ввода
return -1 ;
}
filename[strlen(filename) - 1] = '\0' ;
if (sc_memoryLoad(filename)){
ui_messageOutput((char *)"Failed to load memory", colors::RED) ;
return -1 ;
}
return 0 ;
}
int ui_setAccumulator(){
// может ли в accumulator храниться команда ? (теперь нет)
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"Accumulator\"\033[0m", colors::GREEN) ;
printf("\nEnter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+'){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if(number > 0x3FFF){
ui_messageOutput((char *)"The command value must not exceed 14 bits (0x3FFF)", colors::RED) ;
return -1 ;
}
else
{
number &= 0x3FFF ;
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
else{
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
}
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
sc_accumulator = res ;
return 0 ;
}
int ui_setICounter(){
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"InstructionCounter\"\033[0m between \033[38;5;%dm00\033[0m and \033[38;5;%dm99\033[0m inclusive\n", colors::GREEN, colors::SOFT_GREEN, colors::SOFT_GREEN) ;
printf("Enter value in \033[38;5;%dmDEC\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
if (!checkCorrectInputDEC(buffer)){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(buffer, &tmp, 10);
if(number > 99){
ui_messageOutput((char *)"The value must not exceed the amount of memory", colors::RED) ;
return -1 ;
}
sc_instructionCounter = (uint8_t)number ;
return 0 ;
}
/// Отрисовка "боксов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBoxes(){
if (bc_box(1, 1, 61, 12)) // Окно Memory
return -1 ;
if (bc_box(62, 1, 22, 3)) // Окно accumulator
return -1 ;
if (bc_box(62, 4, 22, 3)) // Окно instructionCounter
return -1 ;
if (bc_box(62, 7, 22, 3)) // Окно Operation
return -1 ;
if (bc_box(62, 10, 22, 3)) // Окно Flags
return -1 ;
if (bc_box(1, 13, 52, 10)) // Окно BigChars
return -1 ;
if (bc_box(53, 13, 31, 10)) // Окно Keys
return -1 ;
return 0 ;
}
/// Отрисовка заголовков и текста
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingTexts(){
/* Заголовки */
mt_gotoXY(30,1) ;
printf(" Memory ") ;
mt_gotoXY(66,1) ;
printf(" accumulator ") ;
mt_gotoXY(63,4) ;
printf(" instructionCounter ") ;
mt_gotoXY(67,7) ;
printf(" Operation ") ;
mt_gotoXY(69,10) ;
printf(" Flags ") ;
mt_gotoXY(54,13) ;
printf(" Keys: ") ;
/* HotKeys */
char* hotK[] = {(char *)"l - load",
(char *)"s - save",
(char *)"r - run",
(char *)"t - step",
(char *)"i - reset",
(char *)"F5 - accumulator",
(char *)"F6 - instructionCounter"};
for (int i = 0 ; i < sizeof(hotK) / sizeof(*hotK) ; ++i) {
mt_gotoXY(54,i + 14) ;
printf("%s", hotK[i]) ;
}
return 0 ;
}
/// Отрисовка памяти
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingMemory(){
for (int i = 0 ; i < 10 ; ++i)
for (int j = 0 ; j < 10 ; ++j) {
mt_gotoXY(2 + (5 * j + j), 2 + i) ;
unsigned short int tmp ;
sc_memoryGet(i * 10 + j, &tmp) ;
if ((i * 10 + j) == currMemCell)
mt_setBGcolor(colors::GREEN) ;
if((tmp >> 14) & 1)
if((tmp >> 13) & 1)
printf("-%04X", (
(tmp - 1)) & 0x3FFF) ;
else
printf(" %04X", tmp & 0x1FFF) ;
else
printf("+%04X", tmp) ;
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка accumulator
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingAccumulator(){
mt_gotoXY(70,2) ;
// bool over ;
// sc_regGet(OVERFLOW, &over) ;
// if (over){
// mt_setFGcolor(colors::PEACH) ;
// printf(" over") ;
// mt_setDefaultColorSettings() ;
// }
// else{
if((sc_accumulator >> 14) & 1)
if((sc_accumulator >> 13) & 1)
printf("-%04X", (
(sc_accumulator - 1)) & 0x3FFF) ;
else
printf(" %04X", sc_accumulator & 0x1FFF) ;
else
printf("+%04X", sc_accumulator) ;
// }
return 0 ;
}
/// Отрисовка Operation
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingOperation(){
mt_gotoXY(69,8) ;
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1)){
unsigned short int operand, command ;
sc_commandDecode(tmp, &command, &operand) ;
printf("+%02X:%02X", command, operand) ;
}
else{
unsigned short int left, right ;
bool negative = (tmp >> 13) & 1 ;
if(negative)
tmp = (
(tmp - 1)) & 0x3FFF ;
else
tmp &= 0x1FFF ;
left = tmp >> 8 ;
right = tmp & 0xFF ;
negative ? printf("-%02X:%02X", left, right) : printf(" %02X:%02X", left, right) ;
}
return 0 ;
}
/// Отрисовка instructionCounter
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingInstructionCounter(){
mt_gotoXY(71,5) ;
// bool over, zero, out, comm ;
// sc_regGet(OVERFLOW, &over) ;
// sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
// sc_regGet(OUT_OF_MEMORY, &out) ;
// sc_regGet(INCORRECT_COMMAND, &comm) ;
// mt_gotoXY(71,5) ;
// if (over || zero || out || comm){
// mt_setFGcolor(colors::SOFT_GREEN) ;
// printf("null") ;
// mt_setDefaultColorSettings() ;
// }
// else
printf("%04X", sc_instructionCounter) ;
return 0 ;
}
/// Отрисовка флагов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingFlags(){
char tmp[] = {'O', 'Z', 'M', 'I', 'C'};
for (int i = 0 ; i < SC_REG_SIZE ; ++i) {
bool value ;
if (sc_regGet(i, &value))
return -1 ;
mt_gotoXY(68 + (i * 2), 11) ;
if (value){
mt_setFGcolor(colors::PEACH) ;
printf("%c", tmp[i]) ;
}
else{
mt_setFGcolor(colors::GRAY) ;
printf("%c", tmp[i]) ;
}
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка "BigChar'ов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBigChar(){
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1))
bc_printBigChar(bc[16], 2, 14, GREEN) ;
else if((tmp >> 13) & 1){
bc_printBigChar(bc[17], 2, 14, GREEN) ;
tmp = (
(tmp - 1)) & 0x3FFF;
}
else
tmp &= 0x3FFF ;
for (int i = 0; i < 4; ++i) {
int ch = (tmp & ( 0xF << (4 * (3 - i)) )) >> (4 * (3 - i)) ;
bc_printBigChar(bc[ch], 2 + 8 * (i + 1) + 2 * (i + 1), 14, GREEN) ;
}
return 0 ;
}
bool checkCorrectInputHEX(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 4)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isxdigit(buffer[i])))
return false ;
return true ;
}
bool checkCorrectInputDEC(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 5)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isdigit(buffer[i])))
return false ;
return true ;
}
int ui_messageOutput(char *str, enum colors color){
printf("\033[38;5;%dm%s\033[0m", color, str) ;
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
return 0 ;
}
int clearBuffIn(){
int c;
do {
c = getchar();
} while (c != '\n' && c != '\0');
return 0 ;
}
myReadkey.hpp
#ifndef MYREADKEY_HPP
#define MYREADKEY_HPP
#include
#include
#include
extern termios save;
enum keys
{
KEY_L,
KEY_S,
KEY_R,
KEY_T,
KEY_I,
KEY_F5,
KEY_F6 ,
KEY_UP,
KEY_DOWN,
KEY_RIGHT,
KEY_LEFT,
KEY_ESC,
KEY_ENTER,
KEY_OTHER,
};
int rk_readKey(enum keys *key) ;
int rk_myTermSave() ;
int rk_myTermRestore() ;
int rk_myTermRegime (bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint) ;
#endif //MYREADKEY_HPP
myReadkey.cpp
#include "myReadkey.hpp"
termios save;
/// Возвращающую первую клавишу, которую нажал пользователь
/// \param key - Адрес переменной, в которую возвращается номер нажатой клавиши
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_readKey (enum keys * key){
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
rk_myTermRestore() ;
if (buffer[0] == '\033')
if (buffer[1] == '\0')
*key = KEY_ESC ;
else if (buffer[1] == '[')
if (buffer[2] == 'A' and buffer[3] == '\0')
*key = KEY_UP ;
else if (buffer[2] == 'B' and buffer[3] == '\0')
*key = KEY_DOWN ;
else if (buffer[2] == 'C' and buffer[3] == '\0')
*key = KEY_RIGHT ;
else if (buffer[2] == 'D' and buffer[3] == '\0')
*key = KEY_LEFT ;
else if (buffer[2] == '1' and buffer[3] == '5')
*key = KEY_F5 ;
else if (buffer[2] == '1' and buffer[3] == '7')
*key = KEY_F6 ;
else
*key = KEY_OTHER ;
else
*key = KEY_OTHER ;
else if (buffer[0] == '\n' and buffer[1] == '\0')
*key = KEY_ENTER ;
else
if ((buffer[0] == 'l' or buffer[0] == 'L') and buffer[1] == '\0')
*key = KEY_L ;
else if ((buffer[0] == 's' or buffer[0] == 'S') and buffer[1] == '\0')
*key = KEY_S ;
else if ((buffer[0] == 'r' or buffer[0] == 'R') and buffer[1] == '\0')
*key = KEY_R ;
else if ((buffer[0] == 't' or buffer[0] == 'T') and buffer[1] == '\0')
*key = KEY_T ;
else if ((buffer[0] == 'i' or buffer[0] == 'I') and buffer[1] == '\0')
*key = KEY_I ;
else
*key = KEY_OTHER ;
return 0 ;
}
/// Функция, сохраняющая текущие параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermSave(){
if (tcgetattr(fileno(stdin), &save))
return -1 ;
return 0 ;
}
/// Функция, восстанавливающая сохраненные параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRestore(){
tcsetattr(fileno(stdin), TCSAFLUSH, &save) ;
return 0 ;
}
/// Функция, переключающая режим работы терминала (канонический / неканонический)
/// \param regime
/// \param vtime
/// \param vmin
/// \param echo
/// \param sigint
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRegime(bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint){
termios curr{} ;
tcgetattr(fileno(stdin), &curr) ;
if(regime)
curr.c_lflag |= ICANON ;
else{
curr.c_lflag &=
ICANON ;
sigint ? (curr.c_lflag |= ISIG) : (curr.c_lflag &=
ISIG) ;
echo ? (curr.c_lflag |= ECHO) : (curr.c_lflag &=
ECHO) ;
curr.c_cc[VMIN] = vmin ;
curr.c_cc[VTIME] = vtime ;
}
tcsetattr(0,TCSAFLUSH,&curr) ;
return 0 ;
}
commands.hpp
#ifndef COMMANDS_HPP
#define COMMANDS_HPP
#define READ 0x10
#define WRITE 0x11
#define LOAD 0x20
#define STORE 0x21
#define ADD 0x30
#define SUB 0x31
#define DIVIDE 0x32
#define MUL 0x33
#define JUMP 0x40
#define JNEG 0x41
#define JZ 0x42
#define HALT 0x43
#define RCR 0x63
#endif //COMMANDS_HPP
myCU.hpp
#ifndef CU_HPP
#define CU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
#include "myALU.hpp"
int CU() ;
#endif //CU_HPP
myCU.cpp
#include "myCU.hpp"
int cu_read(unsigned short int operand) ;
int cu_write(unsigned short int operand) ;
int cu_load(unsigned short int operand) ;
int cu_store(unsigned short int operand) ;
int cu_jump(unsigned short int operand) ;
int cu_jneg(unsigned short int operand) ;
int cu_jz(unsigned short int operand) ;
int CU (){
unsigned short int command = 0;
unsigned short int operand = 0;
unsigned short int currCell;
sc_memoryGet(sc_instructionCounter, &currCell) ;
if (sc_commandDecode(currCell, &command, &operand)){
return -1 ;
}
switch (command) {
case READ:
if (cu_read(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case WRITE:
if (cu_write(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case LOAD :
if (cu_load(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case STORE :
if (cu_store(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case JUMP :
if (cu_jump(operand))
return -1 ;
break ;
case JNEG :
if (cu_jneg(operand))
return -1 ;
break ;
case JZ :
if (cu_jz(operand))
return -1 ;
break ;
case HALT :
return -1 ;
break ;
default:
if (ALU(command, operand))
return -1 ;
break ;
}
return 0 ;
}
int cu_read(unsigned short int operand){
rk_myTermRestore() ;
printf("Enter value of cell[\033[38;5;%dm0x%02X\033[0m] in \033[38;5;%dmHEX\033[0m format > ", colors::SOFT_GREEN, operand, colors::PEACH) ;
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
rk_myTermRegime(false, 0, 0, false, false) ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+' or buffer[0] == '-')
i = 1 ;
else{
res |= (1 << 14) ;
(buffer[0] == '-') ? (res |= (1 << 13)) : i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
res |= (1 << 15) ;
}
else{
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if (number > 0x3FFF)
res |= (1 << 15) ;
else
{
number &= 0x3FFF ;
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value)){
res |= (1 << 15) ;
}
else
res |= value ;
}
}
else{
if (number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
res |= (1 << 15) ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
}
if (sc_memorySet(operand, (unsigned short int)res))
return -1 ;
return 0 ;
}
int cu_write(unsigned short int operand){
unsigned short int value;
if(sc_memoryGet(operand, &value)){
return -1 ;
}
printf("Value in a cell [\033[38;5;%dm0x%02X\033[0m] < ", colors::SOFT_GREEN, operand) ;
if ((value >> 14) & 1)
if ((value >> 13) & 1)
printf("-%04X", (
(value - 1)) & 0x3FFF) ;
else
printf(" %04X", value & 0x1FFF) ;
else
printf("+%04X", value) ;
getchar() ;
return 0 ;
}
int cu_load(unsigned short int operand){
unsigned short int value;
if (sc_memoryGet(operand, &value)){
return -1 ;
}
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return - 1;
}
sc_accumulator = value ;
return 0 ;
}
int cu_store(unsigned short int operand){
if (sc_memorySet(operand, sc_accumulator))
return -1 ;
return 0 ;
}
int cu_jump(unsigned short int operand){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
return 0 ;
}
int cu_jneg(unsigned short int operand){
if (((sc_accumulator >> 14) & 1) and ((sc_accumulator >> 13) & 1)){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
}
else
sc_instructionCounter++ ;
return 0 ;
}
int cu_jz(unsigned short int operand){
if (((sc_accumulator >> 14) & 1) and ((sc_accumulator & 0x3FFF) == 0)){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
}
else
sc_instructionCounter++ ;
return 0 ;
}
myALU.hpp
#ifndef MYALU_HPP
#define MYALU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
int ALU(unsigned short int command, unsigned short int operand) ;
#endif //MYALU_HPP
myALU.cpp
#include "myALU.hpp"
int alu_add(unsigned short int value) ;
int alu_divide(unsigned short int operand) ;
int alu_mul(unsigned short int operand) ;
int alu_rcr(unsigned short int operand) ;
int ALU(unsigned short int command, unsigned short int operand){
unsigned short int value ;
switch (command) {
case ADD:
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
if (alu_add(value))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case SUB:
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
if ((value >> 13) & 1) // Отрицательное
value =
((value & 0x3FFF) - 1) ;
else
value = (
(value & 0x3FFF)) + 1 ;
value &= 0x3FFF ;
value |= (1 << 14) ;
if (alu_add(value))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case DIVIDE:
if (alu_divide(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case MUL:
if (alu_mul(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case RCR:
if (alu_rcr(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
default:
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
return 0 ;
}
int alu_add(unsigned short int value){
unsigned short int accumulator, res;
accumulator = sc_accumulator & 0x3FFF ;
value &= 0x3FFF;
if (((accumulator >> 13) & 1) and ((value >> 13) & 1)){ // Если оба отрицательны
value =
(value - 1) & 0x3FFF ;
accumulator =
(accumulator - 1) & 0x3FFF ;
res = accumulator + value;
if (res > 0x2000){
sc_regSet(OVERFLOW, true) ;
}
res =
res + 1 ;
}
else if (((accumulator >> 13) & 1) or ((value >> 13) & 1)) { // Если одно из чисел отрицательно
res = accumulator + value ;
}
else{
res = accumulator + value ;
if (res > 0x1FFF){
sc_regSet(OVERFLOW, true) ;
}
}
res |= (1 << 14) ;
sc_accumulator = res ;
return 0 ;
}
int alu_divide(unsigned short int operand){
unsigned short int value,accumulator, res ;
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
bool negative = 0 ;
accumulator = sc_accumulator & 0x3FFF ;
value &= 0x3FFF;
if ((accumulator >> 13) & 1){
negative = !negative ;
accumulator =
(accumulator - 1);
}
accumulator &= 0x3FFF ;
if ((value >> 13) & 1){
negative = !negative ;
value =
(value - 1);
}
value &= 0x3FFF ;
if (value == 0){
sc_regSet(DIVISION_ERR_BY_ZERO, true) ;
return -1 ;
}
res = accumulator / value ;
if (negative){
if (res > 0x2000){
sc_regSet(OVERFLOW, true) ;
}
res = (
res + 1) & 0x3FFF ;
res |= (1 << 14) ;
sc_accumulator = res ;
}
else {
if (res > 0x1FFF){
sc_regSet(OVERFLOW, true) ;
}
res |= (1 << 14) ;
sc_accumulator = res ;
}
return 0 ;
}
int alu_mul(unsigned short int operand){
unsigned short int value,accumulator, res ;
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
bool negative = 0 ;
accumulator = sc_accumulator & 0x3FFF ;
value &= 0x3FFF;
if ((accumulator >> 13) & 1){
negative = !negative ;
accumulator =
(accumulator - 1);
}
accumulator &= 0x1FFF ;
if ((value >> 13) & 1){
negative = !negative ;
value =
(value - 1);
}
value &= 0x1FFF ;
res = accumulator * value ;
if (negative){
if (res > 0x2000){
sc_regSet(OVERFLOW, true) ;
}
res = (
res + 1) & 0x3FFF ;
Приложение. Листинг
Makefile
d.PHONY: all clean run
COMPILER := g++
FLAGS := -fdiagnostics-color=always -Werror -MMD
SRC_SC := src/sc
BUILD_SC := build/sc
LIBS_SC := libs/sc
SRC_SA := src/sa
BUILD_SA := build/sa
SRC_SB := src/sb
BUILD_SB := build/sb
BIN := bin
SC := simpleComputer
SA := simpleAssembler
SB := simpleBasic
all: create $(BIN)/$(SC) $(BIN)/$(SA) $(BIN)/$(SB)
-include $((BUILD_SC)/*.d
-include $((BUILD_SA)/*.d
-include $((BUILD_SB)/*.d
sc: create $(BIN)/$(SC)
run_sc: sc
./$(BIN)/$(SC)
$(BIN)/$(SC): $(LIBS_SC)/libsimpleComputer.a $(LIBS_SC)/libmyTerm.a $(LIBS_SC)/libmyBigChars.a $(LIBS_SC)/libmyReadkey.a $(LIBS_SC)/libmyUI.a $(LIBS_SC)/libmyALU.a $(LIBS_SC)/libmyCU.a $(BUILD_SC)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SC) $(BUILD_SC)/main.o -L $(LIBS_SC) -lsimpleComputer -lmyUI -lmyTerm -lmyBigChars -lmyReadkey -lmyCU -lmyALU
$(BUILD_SC)/%.o: $(SRC_SC)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
$(LIBS_SC)/libsimpleComputer.a: $(BUILD_SC)/simpleComputer.o
ar cr $@ $^
$(LIBS_SC)/libmyTerm.a: $(BUILD_SC)/myTerm.o
ar cr $@ $^
$(LIBS_SC)/libmyBigChars.a: $(BUILD_SC)/myBigChars.o
ar cr $@ $^
$(LIBS_SC)/libmyReadkey.a: $(BUILD_SC)/myReadkey.o
ar cr $@ $^
$(LIBS_SC)/libmyUI.a: $(BUILD_SC)/myUI.o
ar cr $@ $^
$(LIBS_SC)/libmyALU.a: $(BUILD_SC)/myALU.o
ar cr $@ $^
$(LIBS_SC)/libmyCU.a: $(BUILD_SC)/myCU.o
ar cr $@ $^
sa: create $(BIN)/$(SA)
run_sa: create $(BIN)/$(SA)
./$(BIN)/$(SA)
$(BIN)/$(SA): $(BUILD_SA)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SA) $(BUILD_SA)/main.o
$(BUILD_SA)/%.o: $(SRC_SA)/%.cpps
$(COMPILER) $(FLAGS) -c $^ -o $@
sb: create $(BIN)/$(SB)
run_sb: create $(BIN)/$(SB)
./$(BIN)/$(SB)
$(BIN)/$(SB): $(BUILD_SB)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SB) $(BUILD_SB)/main.o
$(BUILD_SB)/%.o: $(SRC_SB)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
create:
mkdir -p $(BUILD_SC) $(BUILD_SA) $(BUILD_SB) $(LIBS_SC) $(BIN)
clean:
@rm -rf build libs $(BIN)
SimpleComputer
main.cpp
#include
#include "simpleComputer.hpp"
#include "myUI.hpp"
#include "myReadkey.hpp"
#include "myCU.hpp"
void signalHandler(int signal) ;
#include
int main(int argc, char const *argv[]){
ui_initial() ;
signal(SIGALRM, signalHandler) ;
signal(SIGUSR1, signalHandler) ;
bool zero, out, ignor, comm ;
keys key;
if (argc == 2){
sc_memoryLoad((char *)argv[1]) ;
}
else if (argc > 2){
ui_messageOutput((char *)"Exceeded the number of arguments", colors::RED) ;
return -1 ;
}
do {
sc_regGet(IGNORING_TACT_PULSES, &ignor);
ui_update() ;
rk_readKey(&key);
if (ignor){
sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
sc_regGet(OUT_OF_MEMORY, &out) ;
sc_regGet(INCORRECT_COMMAND, &comm) ;
if (zero || out || comm){
switch(key){
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
}
}
else{
switch(key){
case keys::KEY_UP:
ui_moveCurrMemPointer(keys::KEY_UP) ;
break ;
case keys::KEY_RIGHT:
ui_moveCurrMemPointer(keys::KEY_RIGHT) ;
break ;
case keys::KEY_DOWN:
ui_moveCurrMemPointer(keys::KEY_DOWN) ;
break ;
case keys::KEY_LEFT:
ui_moveCurrMemPointer(keys::KEY_LEFT) ;
break ;
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_R:
sc_regInit() ;
raise(SIGALRM) ;
break ;
case keys::KEY_T:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
CU() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
case keys::KEY_F5:
ui_setAccumulator() ;
break ;
case keys::KEY_F6:
ui_setICounter() ;
break ;
case keys::KEY_ENTER:
ui_setMCellValue() ;
break ;
}
}
}
else
if (key == keys::KEY_I)
raise(SIGUSR1) ;
} while(key != keys::KEY_ESC) ;
return 0 ;
}
void signalHandler(int signal){
switch (signal) {
case SIGALRM:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
if (CU()){
sc_regSet(IGNORING_TACT_PULSES, true);
ui_update() ;
alarm(0) ;
}
else
alarm(1) ;
rk_myTermRegime(false, 0, 0, false, false) ;
break ;
case SIGUSR1:
alarm(0) ;
ui_initial() ;
break ;
default:
break ;
}
}
simpleComputer.hpp
#ifndef SIMPLECOMPUTER_HPP
#define SIMPLECOMPUTER_HPP
#include
#define OVERFLOW 0 // Переполнение при выполнении операции
#define DIVISION_ERR_BY_ZERO 1 // Ошибка деления на 0
#define OUT_OF_MEMORY 2 // Ошибка выхода за границы памяти
#define IGNORING_TACT_PULSES 3 // Игнорирование тактовых импульсов
#define INCORRECT_COMMAND 4 // Указана неверная команда
const short int SC_REG_SIZE = 5 ;
const short int SC_MEM_SIZE = 100 ;
extern unsigned short int sc_accumulator ;
extern uint8_t sc_instructionCounter ;
int sc_memoryInit () ;
int sc_memorySet (unsigned short int address, unsigned short int value) ;
int sc_memoryGet (unsigned short int address, unsigned short int * value) ;
int sc_memorySave (char* filename) ;
int sc_memoryLoad (char* filename) ;
int sc_regInit () ;
int sc_regSet (int8_t reg, bool value) ;
int sc_regGet (int8_t reg, bool * value) ;
int sc_commandEncode (unsigned short int command, unsigned short int operand, unsigned short int * value) ;
int sc_commandDecode (unsigned short int value, unsigned short int * command, unsigned short int * operand) ;
#endif //SIMPLECOMPUTER_HPP
simpleComputer.cpp
#include "simpleComputer.hpp"
unsigned short int sc_memory[SC_MEM_SIZE] ;
uint8_t sc_regFLAGS ;
unsigned short int sc_accumulator ;
uint8_t sc_instructionCounter ;
/// Инициализирует оперативную память SC, задавая всем её ячейкам нулевые значения
/// \return 0
int sc_memoryInit()
{
sc_instructionCounter = 0 ;
for (unsigned short & mem : sc_memory)
mem = 0 ;
return 0 ;
}
/// Задает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySet(unsigned short int address, unsigned short int value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_memory[address] = value ;
return 0 ;
}
/// Возвращает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryGet(unsigned short int address, unsigned short int * value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
*value = sc_memory[address] ;
return 0 ;
}
/// Сохраняет содержимое памяти в файл в бинарном виде
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySave(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "wb"))){
return -1 ;
}
fwrite(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Загружает из указанного файла содержимое оперативной памяти
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryLoad(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "rb"))){
return -1 ;
}
fread(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Инициализирует регистр флагов нулевым значением
/// \return 0
int sc_regInit(){
sc_regFLAGS = 0 ;
return 0 ;
}
/// Устанавливает значение указанного регистра флагов
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regSet(int8_t reg, bool value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
value == 1 ? (sc_regFLAGS |= (1 << reg)) : (sc_regFLAGS &=
(1 << reg)) ;
return 0 ;
}
/// Возвращает значение указанного флага
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regGet(int8_t reg, bool *value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
*value = sc_regFLAGS & (1 << reg) ;
return 0 ;
}
/// Кодирует команду с указанным номером и операндом и помещает результат в value
/// \param command - команда
/// \param operand - операнд
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandEncode(unsigned short int command, unsigned short int operand, unsigned short int * value){
if (command > 0x7F)
return -1 ;
if (operand > 0x7F)
return -1 ;
* value = 0 ;
/* Операнд */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (operand >> i) & 1 ;
*value |= (bit << i) ;
}
/* Команда */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (command >> i) & 1 ;
*value |= (bit << (i + 7)) ;
}
return 0 ;
}
/// Декодирует значение как команду SС
/// \param value - значение
/// \param command - команда
/// \param operand - операнд
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandDecode(unsigned short int value, unsigned short int * command, unsigned short int * operand){
int tmpCom = 0, tmpOp = 0 ;
if ((value >> 14) & 1){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> i) & 1 ;
tmpOp |= (bit << i) ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> (i + 7)) & 1 ;
tmpCom |= (bit << i) ;
}
* command = tmpCom ;
* operand = tmpOp ;
return 0 ;
}
myTerm.hpp
#ifndef MYTERM_HPP
#define MYTERM_HPP
#include
#include
enum colors {
RED = 196,
PEACH = 203,
GREEN = 10,
SOFT_GREEN =192,
BLUE = 20,
BLACK = 16,
GRAY = 240,
WHITE = 15,
DEFAULT = 0};
int mt_clrScreen () ;
int mt_gotoXY(unsigned int col,unsigned int row) ;
int mt_getScreenSize(unsigned int *rows, unsigned int* cols) ;
int mt_setFGcolor(enum colors color) ;
int mt_setBGcolor(enum colors color) ;
int mt_setDefaultColorSettings() ;
#endif //MYTERM_HPP
myTerm.cpp
#include "myTerm.hpp"
/// Производит очистку и перемещение курсора в левый верхний угол экрана
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_clrScreen (){
printf("\033[H\033[2J") ;
return 0 ;
}
/// Перемещает курсор в указанную позицию
/// \param col - столбец
/// \param row - строка
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_gotoXY(unsigned int col, unsigned int row)
{
unsigned int rows, cols ;
if (mt_getScreenSize(&rows, &cols) == -1)
return -1 ;
if ((row > rows) || (row <= 0)||(col > cols) || (col <= 0))
return -1 ;
printf("\033[%d;%dH", row, col) ;
return 0 ;
}
/// Определяет размер экрана терминала
/// \param rows - кол-во строк
/// \param cols - кол-во столбцов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_getScreenSize(unsigned int *rows, unsigned int *cols){
winsize ws{} ;
if (ioctl(1, TIOCGWINSZ, &ws))
return -1 ;
* rows = ws.ws_row ;
* cols = ws.ws_col ;
return 0 ;
}
/// Устанавливает цвет последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setFGcolor(enum colors color){
printf("\033[38;5;%dm",color) ;
return 0 ;
}
/// Устанавливает цвет фона последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setBGcolor(enum colors color){
printf("\033[48;5;%dm",color) ;
return 0 ;
}
/// Возвращает цвета в стандартное состояние
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setDefaultColorSettings(){
printf("\033[0m") ;
return 0 ;
}
myUI.hpp
#ifndef MYUI_HPP
#define MYUI_HPP
#include
#include "myBigChars.hpp"
#include "myReadkey.hpp"
#include "simpleComputer.hpp"
int ui_initial() ;
int ui_update() ;
int setCurrMemPointer_to_ICounter() ;
int ui_moveCurrMemPointer(keys key) ;
int ui_setMCellValue() ;
int ui_saveMemory() ;
int ui_loadMemory() ;
int ui_setAccumulator() ;
int ui_setICounter() ;
bool checkCorrectInputHEX(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color);
int clearBuffIn() ;
#endif //MYUI_HPP
myUI.cpp
#include "myUI.hpp"
#include "myReadkey.hpp"
int8_t currMemCell = 0 ;
int drawingBoxes() ;
int drawingTexts() ;
int drawingMemory() ;
int drawingAccumulator() ;
int drawingInstructionCounter() ;
int drawingOperation() ;
int drawingFlags() ;
int drawingBigChar() ;
bool checkCorrectInputHEX(const char *buffer) ;
bool checkCorrectInputDEC(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color) ;
/// "Инициализация" интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_initial(){
currMemCell = 0 ;
if (rk_myTermSave())
return -1 ;
sc_memoryInit() ;
sc_accumulator &= (1 << 14) ;
sc_regInit() ;
sc_regSet(IGNORING_TACT_PULSES, true) ;
return 0 ;
}
/// Обновление интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_update(){
mt_clrScreen() ;
if (drawingBoxes())
return -1 ;
if (drawingTexts())
return -1 ;
if (drawingMemory())
return -1 ;
if (drawingAccumulator())
return -1 ;
if (drawingInstructionCounter())
return -1 ;
if (drawingOperation())
return -1 ;
if (drawingFlags())
return -1 ;
if (drawingBigChar())
return -1 ;
mt_gotoXY(1, 23) ;
printf("Input/Output:\n") ;
return 0 ;
}
/// Перемещение выделенной ячейки на значение ICounter
/// \return 0
int setCurrMemPointer_to_ICounter(){
currMemCell = sc_instructionCounter ;
return 0 ;
}
/// Перемещение выделенной ячейки
/// \param key - Клавиша
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_moveCurrMemPointer(keys key){
switch (key) {
case keys::KEY_UP: (currMemCell <= 9) ? (currMemCell = 90 + currMemCell) : (currMemCell -= 10) ; return 0 ;
case keys::KEY_RIGHT: (!((currMemCell + 1) % 10)) ? (currMemCell -= 9) : (currMemCell += 1) ; return 0 ;
case keys::KEY_DOWN: (currMemCell >= 90) ? (currMemCell = currMemCell - 90) : (currMemCell += 10) ; return 0 ;
case keys::KEY_LEFT: (!(currMemCell % 10)) ? (currMemCell += 9) : (currMemCell -= 1) ; return 0 ;
}
return -1 ;
}
int ui_setMCellValue(){
printf("Set the value of the cell under the number \033[38;5;%dm0x%02X\033[0m\n", colors::SOFT_GREEN, currMemCell) ;
printf("Enter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+')
i = 1 ;
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
if (sc_memorySet(currMemCell, res))
return -1 ;
return 0 ;
}
int ui_saveMemory(){
char filename[102] ;
printf("Saving file...\n") ;
printf("Enter the file name to save > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
printf("\033[38;5;%dmThe file name is too long. The length is trimmed to the first 100 characters.\033[0m\n", BLUE) ;
clearBuffIn(); // очистка потока ввода
}
else
filename[strlen(filename) - 1] = '\0' ;
if (sc_memorySave(filename)){
ui_messageOutput((char *)"Failed to save memory", colors::RED) ;
return -1 ;
}
else
ui_messageOutput((char *)"Successful save", colors::GREEN) ;
return 0 ;
}
int ui_loadMemory(){
char filename[102] ;
printf("Loading file...\n") ;
printf("Enter the file name to load > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
ui_messageOutput((char *)"The name of the file to open is too long (up to 100 characters are allowed)", colors::BLUE) ;
clearBuffIn(); // очистка потока ввода
return -1 ;
}
filename[strlen(filename) - 1] = '\0' ;
if (sc_memoryLoad(filename)){
ui_messageOutput((char *)"Failed to load memory", colors::RED) ;
return -1 ;
}
return 0 ;
}
int ui_setAccumulator(){
// может ли в accumulator храниться команда ? (теперь нет)
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"Accumulator\"\033[0m", colors::GREEN) ;
printf("\nEnter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+'){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if(number > 0x3FFF){
ui_messageOutput((char *)"The command value must not exceed 14 bits (0x3FFF)", colors::RED) ;
return -1 ;
}
else
{
number &= 0x3FFF ;
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
else{
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
}
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
sc_accumulator = res ;
return 0 ;
}
int ui_setICounter(){
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"InstructionCounter\"\033[0m between \033[38;5;%dm00\033[0m and \033[38;5;%dm99\033[0m inclusive\n", colors::GREEN, colors::SOFT_GREEN, colors::SOFT_GREEN) ;
printf("Enter value in \033[38;5;%dmDEC\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
if (!checkCorrectInputDEC(buffer)){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(buffer, &tmp, 10);
if(number > 99){
ui_messageOutput((char *)"The value must not exceed the amount of memory", colors::RED) ;
return -1 ;
}
sc_instructionCounter = (uint8_t)number ;
return 0 ;
}
/// Отрисовка "боксов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBoxes(){
if (bc_box(1, 1, 61, 12)) // Окно Memory
return -1 ;
if (bc_box(62, 1, 22, 3)) // Окно accumulator
return -1 ;
if (bc_box(62, 4, 22, 3)) // Окно instructionCounter
return -1 ;
if (bc_box(62, 7, 22, 3)) // Окно Operation
return -1 ;
if (bc_box(62, 10, 22, 3)) // Окно Flags
return -1 ;
if (bc_box(1, 13, 52, 10)) // Окно BigChars
return -1 ;
if (bc_box(53, 13, 31, 10)) // Окно Keys
return -1 ;
return 0 ;
}
/// Отрисовка заголовков и текста
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingTexts(){
/* Заголовки */
mt_gotoXY(30,1) ;
printf(" Memory ") ;
mt_gotoXY(66,1) ;
printf(" accumulator ") ;
mt_gotoXY(63,4) ;
printf(" instructionCounter ") ;
mt_gotoXY(67,7) ;
printf(" Operation ") ;
mt_gotoXY(69,10) ;
printf(" Flags ") ;
mt_gotoXY(54,13) ;
printf(" Keys: ") ;
/* HotKeys */
char* hotK[] = {(char *)"l - load",
(char *)"s - save",
(char *)"r - run",
(char *)"t - step",
(char *)"i - reset",
(char *)"F5 - accumulator",
(char *)"F6 - instructionCounter"};
for (int i = 0 ; i < sizeof(hotK) / sizeof(*hotK) ; ++i) {
mt_gotoXY(54,i + 14) ;
printf("%s", hotK[i]) ;
}
return 0 ;
}
/// Отрисовка памяти
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingMemory(){
for (int i = 0 ; i < 10 ; ++i)
for (int j = 0 ; j < 10 ; ++j) {
mt_gotoXY(2 + (5 * j + j), 2 + i) ;
unsigned short int tmp ;
sc_memoryGet(i * 10 + j, &tmp) ;
if ((i * 10 + j) == currMemCell)
mt_setBGcolor(colors::GREEN) ;
if((tmp >> 14) & 1)
if((tmp >> 13) & 1)
printf("-%04X", (
(tmp - 1)) & 0x3FFF) ;
else
printf(" %04X", tmp & 0x1FFF) ;
else
printf("+%04X", tmp) ;
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка accumulator
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingAccumulator(){
mt_gotoXY(70,2) ;
// bool over ;
// sc_regGet(OVERFLOW, &over) ;
// if (over){
// mt_setFGcolor(colors::PEACH) ;
// printf(" over") ;
// mt_setDefaultColorSettings() ;
// }
// else{
if((sc_accumulator >> 14) & 1)
if((sc_accumulator >> 13) & 1)
printf("-%04X", (
(sc_accumulator - 1)) & 0x3FFF) ;
else
printf(" %04X", sc_accumulator & 0x1FFF) ;
else
printf("+%04X", sc_accumulator) ;
// }
return 0 ;
}
/// Отрисовка Operation
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingOperation(){
mt_gotoXY(69,8) ;
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1)){
unsigned short int operand, command ;
sc_commandDecode(tmp, &command, &operand) ;
printf("+%02X:%02X", command, operand) ;
}
else{
unsigned short int left, right ;
bool negative = (tmp >> 13) & 1 ;
if(negative)
tmp = (
(tmp - 1)) & 0x3FFF ;
else
tmp &= 0x1FFF ;
left = tmp >> 8 ;
right = tmp & 0xFF ;
negative ? printf("-%02X:%02X", left, right) : printf(" %02X:%02X", left, right) ;
}
return 0 ;
}
/// Отрисовка instructionCounter
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingInstructionCounter(){
mt_gotoXY(71,5) ;
// bool over, zero, out, comm ;
// sc_regGet(OVERFLOW, &over) ;
// sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
// sc_regGet(OUT_OF_MEMORY, &out) ;
// sc_regGet(INCORRECT_COMMAND, &comm) ;
// mt_gotoXY(71,5) ;
// if (over || zero || out || comm){
// mt_setFGcolor(colors::SOFT_GREEN) ;
// printf("null") ;
// mt_setDefaultColorSettings() ;
// }
// else
printf("%04X", sc_instructionCounter) ;
return 0 ;
}
/// Отрисовка флагов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingFlags(){
char tmp[] = {'O', 'Z', 'M', 'I', 'C'};
for (int i = 0 ; i < SC_REG_SIZE ; ++i) {
bool value ;
if (sc_regGet(i, &value))
return -1 ;
mt_gotoXY(68 + (i * 2), 11) ;
if (value){
mt_setFGcolor(colors::PEACH) ;
printf("%c", tmp[i]) ;
}
else{
mt_setFGcolor(colors::GRAY) ;
printf("%c", tmp[i]) ;
}
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка "BigChar'ов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBigChar(){
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1))
bc_printBigChar(bc[16], 2, 14, GREEN) ;
else if((tmp >> 13) & 1){
bc_printBigChar(bc[17], 2, 14, GREEN) ;
tmp = (
(tmp - 1)) & 0x3FFF;
}
else
tmp &= 0x3FFF ;
for (int i = 0; i < 4; ++i) {
int ch = (tmp & ( 0xF << (4 * (3 - i)) )) >> (4 * (3 - i)) ;
bc_printBigChar(bc[ch], 2 + 8 * (i + 1) + 2 * (i + 1), 14, GREEN) ;
}
return 0 ;
}
bool checkCorrectInputHEX(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 4)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isxdigit(buffer[i])))
return false ;
return true ;
}
bool checkCorrectInputDEC(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 5)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isdigit(buffer[i])))
return false ;
return true ;
}
int ui_messageOutput(char *str, enum colors color){
printf("\033[38;5;%dm%s\033[0m", color, str) ;
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
return 0 ;
}
int clearBuffIn(){
int c;
do {
c = getchar();
} while (c != '\n' && c != '\0');
return 0 ;
}
myReadkey.hpp
#ifndef MYREADKEY_HPP
#define MYREADKEY_HPP
#include
#include
#include
extern termios save;
enum keys
{
KEY_L,
KEY_S,
KEY_R,
KEY_T,
KEY_I,
KEY_F5,
KEY_F6 ,
KEY_UP,
KEY_DOWN,
KEY_RIGHT,
KEY_LEFT,
KEY_ESC,
KEY_ENTER,
KEY_OTHER,
};
int rk_readKey(enum keys *key) ;
int rk_myTermSave() ;
int rk_myTermRestore() ;
int rk_myTermRegime (bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint) ;
#endif //MYREADKEY_HPP
myReadkey.cpp
#include "myReadkey.hpp"
termios save;
/// Возвращающую первую клавишу, которую нажал пользователь
/// \param key - Адрес переменной, в которую возвращается номер нажатой клавиши
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_readKey (enum keys * key){
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
rk_myTermRestore() ;
if (buffer[0] == '\033')
if (buffer[1] == '\0')
*key = KEY_ESC ;
else if (buffer[1] == '[')
if (buffer[2] == 'A' and buffer[3] == '\0')
*key = KEY_UP ;
else if (buffer[2] == 'B' and buffer[3] == '\0')
*key = KEY_DOWN ;
else if (buffer[2] == 'C' and buffer[3] == '\0')
*key = KEY_RIGHT ;
else if (buffer[2] == 'D' and buffer[3] == '\0')
*key = KEY_LEFT ;
else if (buffer[2] == '1' and buffer[3] == '5')
*key = KEY_F5 ;
else if (buffer[2] == '1' and buffer[3] == '7')
*key = KEY_F6 ;
else
*key = KEY_OTHER ;
else
*key = KEY_OTHER ;
else if (buffer[0] == '\n' and buffer[1] == '\0')
*key = KEY_ENTER ;
else
if ((buffer[0] == 'l' or buffer[0] == 'L') and buffer[1] == '\0')
*key = KEY_L ;
else if ((buffer[0] == 's' or buffer[0] == 'S') and buffer[1] == '\0')
*key = KEY_S ;
else if ((buffer[0] == 'r' or buffer[0] == 'R') and buffer[1] == '\0')
*key = KEY_R ;
else if ((buffer[0] == 't' or buffer[0] == 'T') and buffer[1] == '\0')
*key = KEY_T ;
else if ((buffer[0] == 'i' or buffer[0] == 'I') and buffer[1] == '\0')
*key = KEY_I ;
else
*key = KEY_OTHER ;
return 0 ;
}
/// Функция, сохраняющая текущие параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermSave(){
if (tcgetattr(fileno(stdin), &save))
return -1 ;
return 0 ;
}
/// Функция, восстанавливающая сохраненные параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRestore(){
tcsetattr(fileno(stdin), TCSAFLUSH, &save) ;
return 0 ;
}
/// Функция, переключающая режим работы терминала (канонический / неканонический)
/// \param regime
/// \param vtime
/// \param vmin
/// \param echo
/// \param sigint
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRegime(bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint){
termios curr{} ;
tcgetattr(fileno(stdin), &curr) ;
if(regime)
curr.c_lflag |= ICANON ;
else{
curr.c_lflag &=
ICANON ;
sigint ? (curr.c_lflag |= ISIG) : (curr.c_lflag &=
ISIG) ;
echo ? (curr.c_lflag |= ECHO) : (curr.c_lflag &=
ECHO) ;
curr.c_cc[VMIN] = vmin ;
curr.c_cc[VTIME] = vtime ;
}
tcsetattr(0,TCSAFLUSH,&curr) ;
return 0 ;
}
commands.hpp
#ifndef COMMANDS_HPP
#define COMMANDS_HPP
#define READ 0x10
#define WRITE 0x11
#define LOAD 0x20
#define STORE 0x21
#define ADD 0x30
#define SUB 0x31
#define DIVIDE 0x32
#define MUL 0x33
#define JUMP 0x40
#define JNEG 0x41
#define JZ 0x42
#define HALT 0x43
#define RCR 0x63
#endif //COMMANDS_HPP
myCU.hpp
#ifndef CU_HPP
#define CU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
#include "myALU.hpp"
int CU() ;
#endif //CU_HPP
myCU.cpp
#include "myCU.hpp"
int cu_read(unsigned short int operand) ;
int cu_write(unsigned short int operand) ;
int cu_load(unsigned short int operand) ;
int cu_store(unsigned short int operand) ;
int cu_jump(unsigned short int operand) ;
int cu_jneg(unsigned short int operand) ;
int cu_jz(unsigned short int operand) ;
int CU (){
unsigned short int command = 0;
unsigned short int operand = 0;
unsigned short int currCell;
sc_memoryGet(sc_instructionCounter, &currCell) ;
if (sc_commandDecode(currCell, &command, &operand)){
return -1 ;
}
switch (command) {
case READ:
if (cu_read(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case WRITE:
if (cu_write(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case LOAD :
if (cu_load(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case STORE :
if (cu_store(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case JUMP :
if (cu_jump(operand))
return -1 ;
break ;
case JNEG :
if (cu_jneg(operand))
return -1 ;
break ;
case JZ :
if (cu_jz(operand))
return -1 ;
break ;
case HALT :
return -1 ;
break ;
default:
if (ALU(command, operand))
return -1 ;
break ;
}
return 0 ;
}
int cu_read(unsigned short int operand){
rk_myTermRestore() ;
printf("Enter value of cell[\033[38;5;%dm0x%02X\033[0m] in \033[38;5;%dmHEX\033[0m format > ", colors::SOFT_GREEN, operand, colors::PEACH) ;
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
rk_myTermRegime(false, 0, 0, false, false) ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+' or buffer[0] == '-')
i = 1 ;
else{
res |= (1 << 14) ;
(buffer[0] == '-') ? (res |= (1 << 13)) : i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
res |= (1 << 15) ;
}
else{
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if (number > 0x3FFF)
res |= (1 << 15) ;
else
{
number &= 0x3FFF ;
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value)){
res |= (1 << 15) ;
}
else
res |= value ;
}
}
else{
if (number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
res |= (1 << 15) ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
}
if (sc_memorySet(operand, (unsigned short int)res))
return -1 ;
return 0 ;
}
int cu_write(unsigned short int operand){
unsigned short int value;
if(sc_memoryGet(operand, &value)){
return -1 ;
}
printf("Value in a cell [\033[38;5;%dm0x%02X\033[0m] < ", colors::SOFT_GREEN, operand) ;
if ((value >> 14) & 1)
if ((value >> 13) & 1)
printf("-%04X", (
(value - 1)) & 0x3FFF) ;
else
printf(" %04X", value & 0x1FFF) ;
else
printf("+%04X", value) ;
getchar() ;
return 0 ;
}
int cu_load(unsigned short int operand){
unsigned short int value;
if (sc_memoryGet(operand, &value)){
return -1 ;
}
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return - 1;
}
sc_accumulator = value ;
return 0 ;
}
int cu_store(unsigned short int operand){
if (sc_memorySet(operand, sc_accumulator))
return -1 ;
return 0 ;
}
int cu_jump(unsigned short int operand){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
return 0 ;
}
int cu_jneg(unsigned short int operand){
if (((sc_accumulator >> 14) & 1) and ((sc_accumulator >> 13) & 1)){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
}
else
sc_instructionCounter++ ;
return 0 ;
}
int cu_jz(unsigned short int operand){
if (((sc_accumulator >> 14) & 1) and ((sc_accumulator & 0x3FFF) == 0)){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
}
else
sc_instructionCounter++ ;
return 0 ;
}
myALU.hpp
#ifndef MYALU_HPP
#define MYALU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
int ALU(unsigned short int command, unsigned short int operand) ;
#endif //MYALU_HPP
myALU.cpp
#include "myALU.hpp"
int alu_add(unsigned short int value) ;
int alu_divide(unsigned short int operand) ;
int alu_mul(unsigned short int operand) ;
int alu_rcr(unsigned short int operand) ;
int ALU(unsigned short int command, unsigned short int operand){
unsigned short int value ;
switch (command) {
case ADD:
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
if (alu_add(value))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case SUB:
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
if ((value >> 13) & 1) // Отрицательное
value =
((value & 0x3FFF) - 1) ;
else
value = (
(value & 0x3FFF)) + 1 ;
value &= 0x3FFF ;
value |= (1 << 14) ;
if (alu_add(value))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case DIVIDE:
if (alu_divide(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case MUL:
if (alu_mul(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case RCR:
if (alu_rcr(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
default:
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
return 0 ;
}
int alu_add(unsigned short int value){
unsigned short int accumulator, res;
accumulator = sc_accumulator & 0x3FFF ;
value &= 0x3FFF;
if (((accumulator >> 13) & 1) and ((value >> 13) & 1)){ // Если оба отрицательны
value =
(value - 1) & 0x3FFF ;
accumulator =
(accumulator - 1) & 0x3FFF ;
res = accumulator + value;
if (res > 0x2000){
sc_regSet(OVERFLOW, true) ;
}
res =
res + 1 ;
}
else if (((accumulator >> 13) & 1) or ((value >> 13) & 1)) { // Если одно из чисел отрицательно
res = accumulator + value ;
}
else{
res = accumulator + value ;
if (res > 0x1FFF){
sc_regSet(OVERFLOW, true) ;
}
}
res |= (1 << 14) ;
sc_accumulator = res ;
return 0 ;
}
int alu_divide(unsigned short int operand){
unsigned short int value,accumulator, res ;
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
bool negative = 0 ;
accumulator = sc_accumulator & 0x3FFF ;
value &= 0x3FFF;
if ((accumulator >> 13) & 1){
negative = !negative ;
accumulator =
(accumulator - 1);
}
accumulator &= 0x3FFF ;
if ((value >> 13) & 1){
negative = !negative ;
value =
(value - 1);
}
value &= 0x3FFF ;
if (value == 0){
sc_regSet(DIVISION_ERR_BY_ZERO, true) ;
return -1 ;
}
res = accumulator / value ;
if (negative){
if (res > 0x2000){
sc_regSet(OVERFLOW, true) ;
}
res = (
res + 1) & 0x3FFF ;
res |= (1 << 14) ;
sc_accumulator = res ;
}
else {
if (res > 0x1FFF){
sc_regSet(OVERFLOW, true) ;
}
res |= (1 << 14) ;
sc_accumulator = res ;
}
return 0 ;
}
int alu_mul(unsigned short int operand){
unsigned short int value,accumulator, res ;
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
bool negative = 0 ;
accumulator = sc_accumulator & 0x3FFF ;
value &= 0x3FFF;
if ((accumulator >> 13) & 1){
negative = !negative ;
accumulator =
(accumulator - 1);
Приложение. Листинг
Makefile
d.PHONY: all clean run
COMPILER := g++
FLAGS := -fdiagnostics-color=always -Werror -MMD
SRC_SC := src/sc
BUILD_SC := build/sc
LIBS_SC := libs/sc
SRC_SA := src/sa
BUILD_SA := build/sa
SRC_SB := src/sb
BUILD_SB := build/sb
BIN := bin
SC := simpleComputer
SA := simpleAssembler
SB := simpleBasic
all: create $(BIN)/$(SC) $(BIN)/$(SA) $(BIN)/$(SB)
-include $((BUILD_SC)/*.d
-include $((BUILD_SA)/*.d
-include $((BUILD_SB)/*.d
sc: create $(BIN)/$(SC)
run_sc: sc
./$(BIN)/$(SC)
$(BIN)/$(SC): $(LIBS_SC)/libsimpleComputer.a $(LIBS_SC)/libmyTerm.a $(LIBS_SC)/libmyBigChars.a $(LIBS_SC)/libmyReadkey.a $(LIBS_SC)/libmyUI.a $(LIBS_SC)/libmyALU.a $(LIBS_SC)/libmyCU.a $(BUILD_SC)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SC) $(BUILD_SC)/main.o -L $(LIBS_SC) -lsimpleComputer -lmyUI -lmyTerm -lmyBigChars -lmyReadkey -lmyCU -lmyALU
$(BUILD_SC)/%.o: $(SRC_SC)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
$(LIBS_SC)/libsimpleComputer.a: $(BUILD_SC)/simpleComputer.o
ar cr $@ $^
$(LIBS_SC)/libmyTerm.a: $(BUILD_SC)/myTerm.o
ar cr $@ $^
$(LIBS_SC)/libmyBigChars.a: $(BUILD_SC)/myBigChars.o
ar cr $@ $^
$(LIBS_SC)/libmyReadkey.a: $(BUILD_SC)/myReadkey.o
ar cr $@ $^
$(LIBS_SC)/libmyUI.a: $(BUILD_SC)/myUI.o
ar cr $@ $^
$(LIBS_SC)/libmyALU.a: $(BUILD_SC)/myALU.o
ar cr $@ $^
$(LIBS_SC)/libmyCU.a: $(BUILD_SC)/myCU.o
ar cr $@ $^
sa: create $(BIN)/$(SA)
run_sa: create $(BIN)/$(SA)
./$(BIN)/$(SA)
$(BIN)/$(SA): $(BUILD_SA)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SA) $(BUILD_SA)/main.o
$(BUILD_SA)/%.o: $(SRC_SA)/%.cpps
$(COMPILER) $(FLAGS) -c $^ -o $@
sb: create $(BIN)/$(SB)
run_sb: create $(BIN)/$(SB)
./$(BIN)/$(SB)
$(BIN)/$(SB): $(BUILD_SB)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SB) $(BUILD_SB)/main.o
$(BUILD_SB)/%.o: $(SRC_SB)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
create:
mkdir -p $(BUILD_SC) $(BUILD_SA) $(BUILD_SB) $(LIBS_SC) $(BIN)
clean:
@rm -rf build libs $(BIN)
SimpleComputer
main.cpp
#include
#include "simpleComputer.hpp"
#include "myUI.hpp"
#include "myReadkey.hpp"
#include "myCU.hpp"
void signalHandler(int signal) ;
#include
int main(int argc, char const *argv[]){
ui_initial() ;
signal(SIGALRM, signalHandler) ;
signal(SIGUSR1, signalHandler) ;
bool zero, out, ignor, comm ;
keys key;
if (argc == 2){
sc_memoryLoad((char *)argv[1]) ;
}
else if (argc > 2){
ui_messageOutput((char *)"Exceeded the number of arguments", colors::RED) ;
return -1 ;
}
do {
sc_regGet(IGNORING_TACT_PULSES, &ignor);
ui_update() ;
rk_readKey(&key);
if (ignor){
sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
sc_regGet(OUT_OF_MEMORY, &out) ;
sc_regGet(INCORRECT_COMMAND, &comm) ;
if (zero || out || comm){
switch(key){
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
}
}
else{
switch(key){
case keys::KEY_UP:
ui_moveCurrMemPointer(keys::KEY_UP) ;
break ;
case keys::KEY_RIGHT:
ui_moveCurrMemPointer(keys::KEY_RIGHT) ;
break ;
case keys::KEY_DOWN:
ui_moveCurrMemPointer(keys::KEY_DOWN) ;
break ;
case keys::KEY_LEFT:
ui_moveCurrMemPointer(keys::KEY_LEFT) ;
break ;
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_R:
sc_regInit() ;
raise(SIGALRM) ;
break ;
case keys::KEY_T:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
CU() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
case keys::KEY_F5:
ui_setAccumulator() ;
break ;
case keys::KEY_F6:
ui_setICounter() ;
break ;
case keys::KEY_ENTER:
ui_setMCellValue() ;
break ;
}
}
}
else
if (key == keys::KEY_I)
raise(SIGUSR1) ;
} while(key != keys::KEY_ESC) ;
return 0 ;
}
void signalHandler(int signal){
switch (signal) {
case SIGALRM:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
if (CU()){
sc_regSet(IGNORING_TACT_PULSES, true);
ui_update() ;
alarm(0) ;
}
else
alarm(1) ;
rk_myTermRegime(false, 0, 0, false, false) ;
break ;
case SIGUSR1:
alarm(0) ;
ui_initial() ;
break ;
default:
break ;
}
}
simpleComputer.hpp
#ifndef SIMPLECOMPUTER_HPP
#define SIMPLECOMPUTER_HPP
#include
#define OVERFLOW 0 // Переполнение при выполнении операции
#define DIVISION_ERR_BY_ZERO 1 // Ошибка деления на 0
#define OUT_OF_MEMORY 2 // Ошибка выхода за границы памяти
#define IGNORING_TACT_PULSES 3 // Игнорирование тактовых импульсов
#define INCORRECT_COMMAND 4 // Указана неверная команда
const short int SC_REG_SIZE = 5 ;
const short int SC_MEM_SIZE = 100 ;
extern unsigned short int sc_accumulator ;
extern uint8_t sc_instructionCounter ;
int sc_memoryInit () ;
int sc_memorySet (unsigned short int address, unsigned short int value) ;
int sc_memoryGet (unsigned short int address, unsigned short int * value) ;
int sc_memorySave (char* filename) ;
int sc_memoryLoad (char* filename) ;
int sc_regInit () ;
int sc_regSet (int8_t reg, bool value) ;
int sc_regGet (int8_t reg, bool * value) ;
int sc_commandEncode (unsigned short int command, unsigned short int operand, unsigned short int * value) ;
int sc_commandDecode (unsigned short int value, unsigned short int * command, unsigned short int * operand) ;
#endif //SIMPLECOMPUTER_HPP
simpleComputer.cpp
#include "simpleComputer.hpp"
unsigned short int sc_memory[SC_MEM_SIZE] ;
uint8_t sc_regFLAGS ;
unsigned short int sc_accumulator ;
uint8_t sc_instructionCounter ;
/// Инициализирует оперативную память SC, задавая всем её ячейкам нулевые значения
/// \return 0
int sc_memoryInit()
{
sc_instructionCounter = 0 ;
for (unsigned short & mem : sc_memory)
mem = 0 ;
return 0 ;
}
/// Задает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySet(unsigned short int address, unsigned short int value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_memory[address] = value ;
return 0 ;
}
/// Возвращает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryGet(unsigned short int address, unsigned short int * value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
*value = sc_memory[address] ;
return 0 ;
}
/// Сохраняет содержимое памяти в файл в бинарном виде
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySave(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "wb"))){
return -1 ;
}
fwrite(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Загружает из указанного файла содержимое оперативной памяти
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryLoad(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "rb"))){
return -1 ;
}
fread(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Инициализирует регистр флагов нулевым значением
/// \return 0
int sc_regInit(){
sc_regFLAGS = 0 ;
return 0 ;
}
/// Устанавливает значение указанного регистра флагов
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regSet(int8_t reg, bool value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
value == 1 ? (sc_regFLAGS |= (1 << reg)) : (sc_regFLAGS &=
(1 << reg)) ;
return 0 ;
}
/// Возвращает значение указанного флага
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regGet(int8_t reg, bool *value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
*value = sc_regFLAGS & (1 << reg) ;
return 0 ;
}
/// Кодирует команду с указанным номером и операндом и помещает результат в value
/// \param command - команда
/// \param operand - операнд
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandEncode(unsigned short int command, unsigned short int operand, unsigned short int * value){
if (command > 0x7F)
return -1 ;
if (operand > 0x7F)
return -1 ;
* value = 0 ;
/* Операнд */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (operand >> i) & 1 ;
*value |= (bit << i) ;
}
/* Команда */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (command >> i) & 1 ;
*value |= (bit << (i + 7)) ;
}
return 0 ;
}
/// Декодирует значение как команду SС
/// \param value - значение
/// \param command - команда
/// \param operand - операнд
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandDecode(unsigned short int value, unsigned short int * command, unsigned short int * operand){
int tmpCom = 0, tmpOp = 0 ;
if ((value >> 14) & 1){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> i) & 1 ;
tmpOp |= (bit << i) ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> (i + 7)) & 1 ;
tmpCom |= (bit << i) ;
}
* command = tmpCom ;
* operand = tmpOp ;
return 0 ;
}
myTerm.hpp
#ifndef MYTERM_HPP
#define MYTERM_HPP
#include
#include
enum colors {
RED = 196,
PEACH = 203,
GREEN = 10,
SOFT_GREEN =192,
BLUE = 20,
BLACK = 16,
GRAY = 240,
WHITE = 15,
DEFAULT = 0};
int mt_clrScreen () ;
int mt_gotoXY(unsigned int col,unsigned int row) ;
int mt_getScreenSize(unsigned int *rows, unsigned int* cols) ;
int mt_setFGcolor(enum colors color) ;
int mt_setBGcolor(enum colors color) ;
int mt_setDefaultColorSettings() ;
#endif //MYTERM_HPP
myTerm.cpp
#include "myTerm.hpp"
/// Производит очистку и перемещение курсора в левый верхний угол экрана
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_clrScreen (){
printf("\033[H\033[2J") ;
return 0 ;
}
/// Перемещает курсор в указанную позицию
/// \param col - столбец
/// \param row - строка
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_gotoXY(unsigned int col, unsigned int row)
{
unsigned int rows, cols ;
if (mt_getScreenSize(&rows, &cols) == -1)
return -1 ;
if ((row > rows) || (row <= 0)||(col > cols) || (col <= 0))
return -1 ;
printf("\033[%d;%dH", row, col) ;
return 0 ;
}
/// Определяет размер экрана терминала
/// \param rows - кол-во строк
/// \param cols - кол-во столбцов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_getScreenSize(unsigned int *rows, unsigned int *cols){
winsize ws{} ;
if (ioctl(1, TIOCGWINSZ, &ws))
return -1 ;
* rows = ws.ws_row ;
* cols = ws.ws_col ;
return 0 ;
}
/// Устанавливает цвет последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setFGcolor(enum colors color){
printf("\033[38;5;%dm",color) ;
return 0 ;
}
/// Устанавливает цвет фона последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setBGcolor(enum colors color){
printf("\033[48;5;%dm",color) ;
return 0 ;
}
/// Возвращает цвета в стандартное состояние
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setDefaultColorSettings(){
printf("\033[0m") ;
return 0 ;
}
myUI.hpp
#ifndef MYUI_HPP
#define MYUI_HPP
#include
#include "myBigChars.hpp"
#include "myReadkey.hpp"
#include "simpleComputer.hpp"
int ui_initial() ;
int ui_update() ;
int setCurrMemPointer_to_ICounter() ;
int ui_moveCurrMemPointer(keys key) ;
int ui_setMCellValue() ;
int ui_saveMemory() ;
int ui_loadMemory() ;
int ui_setAccumulator() ;
int ui_setICounter() ;
bool checkCorrectInputHEX(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color);
int clearBuffIn() ;
#endif //MYUI_HPP
myUI.cpp
#include "myUI.hpp"
#include "myReadkey.hpp"
int8_t currMemCell = 0 ;
int drawingBoxes() ;
int drawingTexts() ;
int drawingMemory() ;
int drawingAccumulator() ;
int drawingInstructionCounter() ;
int drawingOperation() ;
int drawingFlags() ;
int drawingBigChar() ;
bool checkCorrectInputHEX(const char *buffer) ;
bool checkCorrectInputDEC(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color) ;
/// "Инициализация" интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_initial(){
currMemCell = 0 ;
if (rk_myTermSave())
return -1 ;
sc_memoryInit() ;
sc_accumulator &= (1 << 14) ;
sc_regInit() ;
sc_regSet(IGNORING_TACT_PULSES, true) ;
return 0 ;
}
/// Обновление интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_update(){
mt_clrScreen() ;
if (drawingBoxes())
return -1 ;
if (drawingTexts())
return -1 ;
if (drawingMemory())
return -1 ;
if (drawingAccumulator())
return -1 ;
if (drawingInstructionCounter())
return -1 ;
if (drawingOperation())
return -1 ;
if (drawingFlags())
return -1 ;
if (drawingBigChar())
return -1 ;
mt_gotoXY(1, 23) ;
printf("Input/Output:\n") ;
return 0 ;
}
/// Перемещение выделенной ячейки на значение ICounter
/// \return 0
int setCurrMemPointer_to_ICounter(){
currMemCell = sc_instructionCounter ;
return 0 ;
}
/// Перемещение выделенной ячейки
/// \param key - Клавиша
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_moveCurrMemPointer(keys key){
switch (key) {
case keys::KEY_UP: (currMemCell <= 9) ? (currMemCell = 90 + currMemCell) : (currMemCell -= 10) ; return 0 ;
case keys::KEY_RIGHT: (!((currMemCell + 1) % 10)) ? (currMemCell -= 9) : (currMemCell += 1) ; return 0 ;
case keys::KEY_DOWN: (currMemCell >= 90) ? (currMemCell = currMemCell - 90) : (currMemCell += 10) ; return 0 ;
case keys::KEY_LEFT: (!(currMemCell % 10)) ? (currMemCell += 9) : (currMemCell -= 1) ; return 0 ;
}
return -1 ;
}
int ui_setMCellValue(){
printf("Set the value of the cell under the number \033[38;5;%dm0x%02X\033[0m\n", colors::SOFT_GREEN, currMemCell) ;
printf("Enter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+')
i = 1 ;
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
if (sc_memorySet(currMemCell, res))
return -1 ;
return 0 ;
}
int ui_saveMemory(){
char filename[102] ;
printf("Saving file...\n") ;
printf("Enter the file name to save > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
printf("\033[38;5;%dmThe file name is too long. The length is trimmed to the first 100 characters.\033[0m\n", BLUE) ;
clearBuffIn(); // очистка потока ввода
}
else
filename[strlen(filename) - 1] = '\0' ;
if (sc_memorySave(filename)){
ui_messageOutput((char *)"Failed to save memory", colors::RED) ;
return -1 ;
}
else
ui_messageOutput((char *)"Successful save", colors::GREEN) ;
return 0 ;
}
int ui_loadMemory(){
char filename[102] ;
printf("Loading file...\n") ;
printf("Enter the file name to load > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
ui_messageOutput((char *)"The name of the file to open is too long (up to 100 characters are allowed)", colors::BLUE) ;
clearBuffIn(); // очистка потока ввода
return -1 ;
}
filename[strlen(filename) - 1] = '\0' ;
if (sc_memoryLoad(filename)){
ui_messageOutput((char *)"Failed to load memory", colors::RED) ;
return -1 ;
}
return 0 ;
}
int ui_setAccumulator(){
// может ли в accumulator храниться команда ? (теперь нет)
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"Accumulator\"\033[0m", colors::GREEN) ;
printf("\nEnter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+'){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if(number > 0x3FFF){
ui_messageOutput((char *)"The command value must not exceed 14 bits (0x3FFF)", colors::RED) ;
return -1 ;
}
else
{
number &= 0x3FFF ;
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
else{
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
}
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
sc_accumulator = res ;
return 0 ;
}
int ui_setICounter(){
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"InstructionCounter\"\033[0m between \033[38;5;%dm00\033[0m and \033[38;5;%dm99\033[0m inclusive\n", colors::GREEN, colors::SOFT_GREEN, colors::SOFT_GREEN) ;
printf("Enter value in \033[38;5;%dmDEC\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
if (!checkCorrectInputDEC(buffer)){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(buffer, &tmp, 10);
if(number > 99){
ui_messageOutput((char *)"The value must not exceed the amount of memory", colors::RED) ;
return -1 ;
}
sc_instructionCounter = (uint8_t)number ;
return 0 ;
}
/// Отрисовка "боксов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBoxes(){
if (bc_box(1, 1, 61, 12)) // Окно Memory
return -1 ;
if (bc_box(62, 1, 22, 3)) // Окно accumulator
return -1 ;
if (bc_box(62, 4, 22, 3)) // Окно instructionCounter
return -1 ;
if (bc_box(62, 7, 22, 3)) // Окно Operation
return -1 ;
if (bc_box(62, 10, 22, 3)) // Окно Flags
return -1 ;
if (bc_box(1, 13, 52, 10)) // Окно BigChars
return -1 ;
if (bc_box(53, 13, 31, 10)) // Окно Keys
return -1 ;
return 0 ;
}
/// Отрисовка заголовков и текста
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingTexts(){
/* Заголовки */
mt_gotoXY(30,1) ;
printf(" Memory ") ;
mt_gotoXY(66,1) ;
printf(" accumulator ") ;
mt_gotoXY(63,4) ;
printf(" instructionCounter ") ;
mt_gotoXY(67,7) ;
printf(" Operation ") ;
mt_gotoXY(69,10) ;
printf(" Flags ") ;
mt_gotoXY(54,13) ;
printf(" Keys: ") ;
/* HotKeys */
char* hotK[] = {(char *)"l - load",
(char *)"s - save",
(char *)"r - run",
(char *)"t - step",
(char *)"i - reset",
(char *)"F5 - accumulator",
(char *)"F6 - instructionCounter"};
for (int i = 0 ; i < sizeof(hotK) / sizeof(*hotK) ; ++i) {
mt_gotoXY(54,i + 14) ;
printf("%s", hotK[i]) ;
}
return 0 ;
}
/// Отрисовка памяти
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingMemory(){
for (int i = 0 ; i < 10 ; ++i)
for (int j = 0 ; j < 10 ; ++j) {
mt_gotoXY(2 + (5 * j + j), 2 + i) ;
unsigned short int tmp ;
sc_memoryGet(i * 10 + j, &tmp) ;
if ((i * 10 + j) == currMemCell)
mt_setBGcolor(colors::GREEN) ;
if((tmp >> 14) & 1)
if((tmp >> 13) & 1)
printf("-%04X", (
(tmp - 1)) & 0x3FFF) ;
else
printf(" %04X", tmp & 0x1FFF) ;
else
printf("+%04X", tmp) ;
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка accumulator
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingAccumulator(){
mt_gotoXY(70,2) ;
// bool over ;
// sc_regGet(OVERFLOW, &over) ;
// if (over){
// mt_setFGcolor(colors::PEACH) ;
// printf(" over") ;
// mt_setDefaultColorSettings() ;
// }
// else{
if((sc_accumulator >> 14) & 1)
if((sc_accumulator >> 13) & 1)
printf("-%04X", (
(sc_accumulator - 1)) & 0x3FFF) ;
else
printf(" %04X", sc_accumulator & 0x1FFF) ;
else
printf("+%04X", sc_accumulator) ;
// }
return 0 ;
}
/// Отрисовка Operation
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingOperation(){
mt_gotoXY(69,8) ;
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1)){
unsigned short int operand, command ;
sc_commandDecode(tmp, &command, &operand) ;
printf("+%02X:%02X", command, operand) ;
}
else{
unsigned short int left, right ;
bool negative = (tmp >> 13) & 1 ;
if(negative)
tmp = (
(tmp - 1)) & 0x3FFF ;
else
tmp &= 0x1FFF ;
left = tmp >> 8 ;
right = tmp & 0xFF ;
negative ? printf("-%02X:%02X", left, right) : printf(" %02X:%02X", left, right) ;
}
return 0 ;
}
/// Отрисовка instructionCounter
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingInstructionCounter(){
mt_gotoXY(71,5) ;
// bool over, zero, out, comm ;
// sc_regGet(OVERFLOW, &over) ;
// sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
// sc_regGet(OUT_OF_MEMORY, &out) ;
// sc_regGet(INCORRECT_COMMAND, &comm) ;
// mt_gotoXY(71,5) ;
// if (over || zero || out || comm){
// mt_setFGcolor(colors::SOFT_GREEN) ;
// printf("null") ;
// mt_setDefaultColorSettings() ;
// }
// else
printf("%04X", sc_instructionCounter) ;
return 0 ;
}
/// Отрисовка флагов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingFlags(){
char tmp[] = {'O', 'Z', 'M', 'I', 'C'};
for (int i = 0 ; i < SC_REG_SIZE ; ++i) {
bool value ;
if (sc_regGet(i, &value))
return -1 ;
mt_gotoXY(68 + (i * 2), 11) ;
if (value){
mt_setFGcolor(colors::PEACH) ;
printf("%c", tmp[i]) ;
}
else{
mt_setFGcolor(colors::GRAY) ;
printf("%c", tmp[i]) ;
}
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка "BigChar'ов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBigChar(){
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1))
bc_printBigChar(bc[16], 2, 14, GREEN) ;
else if((tmp >> 13) & 1){
bc_printBigChar(bc[17], 2, 14, GREEN) ;
tmp = (
(tmp - 1)) & 0x3FFF;
}
else
tmp &= 0x3FFF ;
for (int i = 0; i < 4; ++i) {
int ch = (tmp & ( 0xF << (4 * (3 - i)) )) >> (4 * (3 - i)) ;
bc_printBigChar(bc[ch], 2 + 8 * (i + 1) + 2 * (i + 1), 14, GREEN) ;
}
return 0 ;
}
bool checkCorrectInputHEX(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 4)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isxdigit(buffer[i])))
return false ;
return true ;
}
bool checkCorrectInputDEC(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 5)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isdigit(buffer[i])))
return false ;
return true ;
}
int ui_messageOutput(char *str, enum colors color){
printf("\033[38;5;%dm%s\033[0m", color, str) ;
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
return 0 ;
}
int clearBuffIn(){
int c;
do {
c = getchar();
} while (c != '\n' && c != '\0');
return 0 ;
}
myReadkey.hpp
#ifndef MYREADKEY_HPP
#define MYREADKEY_HPP
#include
#include
#include
extern termios save;
enum keys
{
KEY_L,
KEY_S,
KEY_R,
KEY_T,
KEY_I,
KEY_F5,
KEY_F6 ,
KEY_UP,
KEY_DOWN,
KEY_RIGHT,
KEY_LEFT,
KEY_ESC,
KEY_ENTER,
KEY_OTHER,
};
int rk_readKey(enum keys *key) ;
int rk_myTermSave() ;
int rk_myTermRestore() ;
int rk_myTermRegime (bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint) ;
#endif //MYREADKEY_HPP
myReadkey.cpp
#include "myReadkey.hpp"
termios save;
/// Возвращающую первую клавишу, которую нажал пользователь
/// \param key - Адрес переменной, в которую возвращается номер нажатой клавиши
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_readKey (enum keys * key){
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
rk_myTermRestore() ;
if (buffer[0] == '\033')
if (buffer[1] == '\0')
*key = KEY_ESC ;
else if (buffer[1] == '[')
if (buffer[2] == 'A' and buffer[3] == '\0')
*key = KEY_UP ;
else if (buffer[2] == 'B' and buffer[3] == '\0')
*key = KEY_DOWN ;
else if (buffer[2] == 'C' and buffer[3] == '\0')
*key = KEY_RIGHT ;
else if (buffer[2] == 'D' and buffer[3] == '\0')
*key = KEY_LEFT ;
else if (buffer[2] == '1' and buffer[3] == '5')
*key = KEY_F5 ;
else if (buffer[2] == '1' and buffer[3] == '7')
*key = KEY_F6 ;
else
*key = KEY_OTHER ;
else
*key = KEY_OTHER ;
else if (buffer[0] == '\n' and buffer[1] == '\0')
*key = KEY_ENTER ;
else
if ((buffer[0] == 'l' or buffer[0] == 'L') and buffer[1] == '\0')
*key = KEY_L ;
else if ((buffer[0] == 's' or buffer[0] == 'S') and buffer[1] == '\0')
*key = KEY_S ;
else if ((buffer[0] == 'r' or buffer[0] == 'R') and buffer[1] == '\0')
*key = KEY_R ;
else if ((buffer[0] == 't' or buffer[0] == 'T') and buffer[1] == '\0')
*key = KEY_T ;
else if ((buffer[0] == 'i' or buffer[0] == 'I') and buffer[1] == '\0')
*key = KEY_I ;
else
*key = KEY_OTHER ;
return 0 ;
}
/// Функция, сохраняющая текущие параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermSave(){
if (tcgetattr(fileno(stdin), &save))
return -1 ;
return 0 ;
}
/// Функция, восстанавливающая сохраненные параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRestore(){
tcsetattr(fileno(stdin), TCSAFLUSH, &save) ;
return 0 ;
}
/// Функция, переключающая режим работы терминала (канонический / неканонический)
/// \param regime
/// \param vtime
/// \param vmin
/// \param echo
/// \param sigint
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRegime(bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint){
termios curr{} ;
tcgetattr(fileno(stdin), &curr) ;
if(regime)
curr.c_lflag |= ICANON ;
else{
curr.c_lflag &=
ICANON ;
sigint ? (curr.c_lflag |= ISIG) : (curr.c_lflag &=
ISIG) ;
echo ? (curr.c_lflag |= ECHO) : (curr.c_lflag &=
ECHO) ;
curr.c_cc[VMIN] = vmin ;
curr.c_cc[VTIME] = vtime ;
}
tcsetattr(0,TCSAFLUSH,&curr) ;
return 0 ;
}
commands.hpp
#ifndef COMMANDS_HPP
#define COMMANDS_HPP
#define READ 0x10
#define WRITE 0x11
#define LOAD 0x20
#define STORE 0x21
#define ADD 0x30
#define SUB 0x31
#define DIVIDE 0x32
#define MUL 0x33
#define JUMP 0x40
#define JNEG 0x41
#define JZ 0x42
#define HALT 0x43
#define RCR 0x63
#endif //COMMANDS_HPP
myCU.hpp
#ifndef CU_HPP
#define CU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
#include "myALU.hpp"
int CU() ;
#endif //CU_HPP
myCU.cpp
#include "myCU.hpp"
int cu_read(unsigned short int operand) ;
int cu_write(unsigned short int operand) ;
int cu_load(unsigned short int operand) ;
int cu_store(unsigned short int operand) ;
int cu_jump(unsigned short int operand) ;
int cu_jneg(unsigned short int operand) ;
int cu_jz(unsigned short int operand) ;
int CU (){
unsigned short int command = 0;
unsigned short int operand = 0;
unsigned short int currCell;
sc_memoryGet(sc_instructionCounter, &currCell) ;
if (sc_commandDecode(currCell, &command, &operand)){
return -1 ;
}
switch (command) {
case READ:
if (cu_read(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case WRITE:
if (cu_write(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case LOAD :
if (cu_load(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case STORE :
if (cu_store(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case JUMP :
if (cu_jump(operand))
return -1 ;
break ;
case JNEG :
if (cu_jneg(operand))
return -1 ;
break ;
case JZ :
if (cu_jz(operand))
return -1 ;
break ;
case HALT :
return -1 ;
break ;
default:
if (ALU(command, operand))
return -1 ;
break ;
}
return 0 ;
}
int cu_read(unsigned short int operand){
rk_myTermRestore() ;
printf("Enter value of cell[\033[38;5;%dm0x%02X\033[0m] in \033[38;5;%dmHEX\033[0m format > ", colors::SOFT_GREEN, operand, colors::PEACH) ;
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
rk_myTermRegime(false, 0, 0, false, false) ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+' or buffer[0] == '-')
i = 1 ;
else{
res |= (1 << 14) ;
(buffer[0] == '-') ? (res |= (1 << 13)) : i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
res |= (1 << 15) ;
}
else{
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if (number > 0x3FFF)
res |= (1 << 15) ;
else
{
number &= 0x3FFF ;
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value)){
res |= (1 << 15) ;
}
else
res |= value ;
}
}
else{
if (number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
res |= (1 << 15) ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
}
if (sc_memorySet(operand, (unsigned short int)res))
return -1 ;
return 0 ;
}
int cu_write(unsigned short int operand){
unsigned short int value;
if(sc_memoryGet(operand, &value)){
return -1 ;
}
printf("Value in a cell [\033[38;5;%dm0x%02X\033[0m] < ", colors::SOFT_GREEN, operand) ;
if ((value >> 14) & 1)
if ((value >> 13) & 1)
printf("-%04X", (
(value - 1)) & 0x3FFF) ;
else
printf(" %04X", value & 0x1FFF) ;
else
printf("+%04X", value) ;
getchar() ;
return 0 ;
}
int cu_load(unsigned short int operand){
unsigned short int value;
if (sc_memoryGet(operand, &value)){
return -1 ;
}
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return - 1;
}
sc_accumulator = value ;
return 0 ;
}
int cu_store(unsigned short int operand){
if (sc_memorySet(operand, sc_accumulator))
return -1 ;
return 0 ;
}
int cu_jump(unsigned short int operand){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
return 0 ;
}
int cu_jneg(unsigned short int operand){
if (((sc_accumulator >> 14) & 1) and ((sc_accumulator >> 13) & 1)){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
}
else
sc_instructionCounter++ ;
return 0 ;
}
int cu_jz(unsigned short int operand){
if (((sc_accumulator >> 14) & 1) and ((sc_accumulator & 0x3FFF) == 0)){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
}
else
sc_instructionCounter++ ;
return 0 ;
}
myALU.hpp
#ifndef MYALU_HPP
#define MYALU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
int ALU(unsigned short int command, unsigned short int operand) ;
#endif //MYALU_HPP
myALU.cpp
#include "myALU.hpp"
int alu_add(unsigned short int value) ;
int alu_divide(unsigned short int operand) ;
int alu_mul(unsigned short int operand) ;
int alu_rcr(unsigned short int operand) ;
int ALU(unsigned short int command, unsigned short int operand){
unsigned short int value ;
switch (command) {
case ADD:
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
if (alu_add(value))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case SUB:
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
if ((value >> 13) & 1) // Отрицательное
value =
((value & 0x3FFF) - 1) ;
else
value = (
(value & 0x3FFF)) + 1 ;
value &= 0x3FFF ;
value |= (1 << 14) ;
if (alu_add(value))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case DIVIDE:
if (alu_divide(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case MUL:
if (alu_mul(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case RCR:
if (alu_rcr(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
default:
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
return 0 ;
}
int alu_add(unsigned short int value){
unsigned short int accumulator, res;
accumulator = sc_accumulator & 0x3FFF ;
value &= 0x3FFF;
if (((accumulator >> 13) & 1) and ((value >> 13) & 1)){ // Если оба отрицательны
value =
(value - 1) & 0x3FFF ;
accumulator =
(accumulator - 1) & 0x3FFF ;
res = accumulator + value;
if (res > 0x2000){
sc_regSet(OVERFLOW, true) ;
}
res =
res + 1 ;
}
else if (((accumulator >> 13) & 1) or ((value >> 13) & 1)) { // Если одно из чисел отрицательно
res = accumulator + value ;
}
else{
res = accumulator + value ;
if (res > 0x1FFF){
sc_regSet(OVERFLOW, true) ;
}
}
res |= (1 << 14) ;
sc_accumulator = res ;
return 0 ;
}
int alu_divide(unsigned short int operand){
unsigned short int value,accumulator, res ;
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
bool negative = 0 ;
accumulator = sc_accumulator & 0x3FFF ;
value &= 0x3FFF;
if ((accumulator >> 13) & 1){
negative = !negative ;
accumulator =
(accumulator - 1);
}
accumulator &= 0x3FFF ;
if ((value >> 13) & 1){
negative = !negative ;
value =
(value - 1);
Приложение. Листинг
Makefile
d.PHONY: all clean run
COMPILER := g++
FLAGS := -fdiagnostics-color=always -Werror -MMD
SRC_SC := src/sc
BUILD_SC := build/sc
LIBS_SC := libs/sc
SRC_SA := src/sa
BUILD_SA := build/sa
SRC_SB := src/sb
BUILD_SB := build/sb
BIN := bin
SC := simpleComputer
SA := simpleAssembler
SB := simpleBasic
all: create $(BIN)/$(SC) $(BIN)/$(SA) $(BIN)/$(SB)
-include $((BUILD_SC)/*.d
-include $((BUILD_SA)/*.d
-include $((BUILD_SB)/*.d
sc: create $(BIN)/$(SC)
run_sc: sc
./$(BIN)/$(SC)
$(BIN)/$(SC): $(LIBS_SC)/libsimpleComputer.a $(LIBS_SC)/libmyTerm.a $(LIBS_SC)/libmyBigChars.a $(LIBS_SC)/libmyReadkey.a $(LIBS_SC)/libmyUI.a $(LIBS_SC)/libmyALU.a $(LIBS_SC)/libmyCU.a $(BUILD_SC)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SC) $(BUILD_SC)/main.o -L $(LIBS_SC) -lsimpleComputer -lmyUI -lmyTerm -lmyBigChars -lmyReadkey -lmyCU -lmyALU
$(BUILD_SC)/%.o: $(SRC_SC)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
$(LIBS_SC)/libsimpleComputer.a: $(BUILD_SC)/simpleComputer.o
ar cr $@ $^
$(LIBS_SC)/libmyTerm.a: $(BUILD_SC)/myTerm.o
ar cr $@ $^
$(LIBS_SC)/libmyBigChars.a: $(BUILD_SC)/myBigChars.o
ar cr $@ $^
$(LIBS_SC)/libmyReadkey.a: $(BUILD_SC)/myReadkey.o
ar cr $@ $^
$(LIBS_SC)/libmyUI.a: $(BUILD_SC)/myUI.o
ar cr $@ $^
$(LIBS_SC)/libmyALU.a: $(BUILD_SC)/myALU.o
ar cr $@ $^
$(LIBS_SC)/libmyCU.a: $(BUILD_SC)/myCU.o
ar cr $@ $^
sa: create $(BIN)/$(SA)
run_sa: create $(BIN)/$(SA)
./$(BIN)/$(SA)
$(BIN)/$(SA): $(BUILD_SA)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SA) $(BUILD_SA)/main.o
$(BUILD_SA)/%.o: $(SRC_SA)/%.cpps
$(COMPILER) $(FLAGS) -c $^ -o $@
sb: create $(BIN)/$(SB)
run_sb: create $(BIN)/$(SB)
./$(BIN)/$(SB)
$(BIN)/$(SB): $(BUILD_SB)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SB) $(BUILD_SB)/main.o
$(BUILD_SB)/%.o: $(SRC_SB)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
create:
mkdir -p $(BUILD_SC) $(BUILD_SA) $(BUILD_SB) $(LIBS_SC) $(BIN)
clean:
@rm -rf build libs $(BIN)
SimpleComputer
main.cpp
#include
#include "simpleComputer.hpp"
#include "myUI.hpp"
#include "myReadkey.hpp"
#include "myCU.hpp"
void signalHandler(int signal) ;
#include
int main(int argc, char const *argv[]){
ui_initial() ;
signal(SIGALRM, signalHandler) ;
signal(SIGUSR1, signalHandler) ;
bool zero, out, ignor, comm ;
keys key;
if (argc == 2){
sc_memoryLoad((char *)argv[1]) ;
}
else if (argc > 2){
ui_messageOutput((char *)"Exceeded the number of arguments", colors::RED) ;
return -1 ;
}
do {
sc_regGet(IGNORING_TACT_PULSES, &ignor);
ui_update() ;
rk_readKey(&key);
if (ignor){
sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
sc_regGet(OUT_OF_MEMORY, &out) ;
sc_regGet(INCORRECT_COMMAND, &comm) ;
if (zero || out || comm){
switch(key){
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
}
}
else{
switch(key){
case keys::KEY_UP:
ui_moveCurrMemPointer(keys::KEY_UP) ;
break ;
case keys::KEY_RIGHT:
ui_moveCurrMemPointer(keys::KEY_RIGHT) ;
break ;
case keys::KEY_DOWN:
ui_moveCurrMemPointer(keys::KEY_DOWN) ;
break ;
case keys::KEY_LEFT:
ui_moveCurrMemPointer(keys::KEY_LEFT) ;
break ;
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_R:
sc_regInit() ;
raise(SIGALRM) ;
break ;
case keys::KEY_T:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
CU() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
case keys::KEY_F5:
ui_setAccumulator() ;
break ;
case keys::KEY_F6:
ui_setICounter() ;
break ;
case keys::KEY_ENTER:
ui_setMCellValue() ;
break ;
}
}
}
else
if (key == keys::KEY_I)
raise(SIGUSR1) ;
} while(key != keys::KEY_ESC) ;
return 0 ;
}
void signalHandler(int signal){
switch (signal) {
case SIGALRM:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
if (CU()){
sc_regSet(IGNORING_TACT_PULSES, true);
ui_update() ;
alarm(0) ;
}
else
alarm(1) ;
rk_myTermRegime(false, 0, 0, false, false) ;
break ;
case SIGUSR1:
alarm(0) ;
ui_initial() ;
break ;
default:
break ;
}
}
simpleComputer.hpp
#ifndef SIMPLECOMPUTER_HPP
#define SIMPLECOMPUTER_HPP
#include
#define OVERFLOW 0 // Переполнение при выполнении операции
#define DIVISION_ERR_BY_ZERO 1 // Ошибка деления на 0
#define OUT_OF_MEMORY 2 // Ошибка выхода за границы памяти
#define IGNORING_TACT_PULSES 3 // Игнорирование тактовых импульсов
#define INCORRECT_COMMAND 4 // Указана неверная команда
const short int SC_REG_SIZE = 5 ;
const short int SC_MEM_SIZE = 100 ;
extern unsigned short int sc_accumulator ;
extern uint8_t sc_instructionCounter ;
int sc_memoryInit () ;
int sc_memorySet (unsigned short int address, unsigned short int value) ;
int sc_memoryGet (unsigned short int address, unsigned short int * value) ;
int sc_memorySave (char* filename) ;
int sc_memoryLoad (char* filename) ;
int sc_regInit () ;
int sc_regSet (int8_t reg, bool value) ;
int sc_regGet (int8_t reg, bool * value) ;
int sc_commandEncode (unsigned short int command, unsigned short int operand, unsigned short int * value) ;
int sc_commandDecode (unsigned short int value, unsigned short int * command, unsigned short int * operand) ;
#endif //SIMPLECOMPUTER_HPP
simpleComputer.cpp
#include "simpleComputer.hpp"
unsigned short int sc_memory[SC_MEM_SIZE] ;
uint8_t sc_regFLAGS ;
unsigned short int sc_accumulator ;
uint8_t sc_instructionCounter ;
/// Инициализирует оперативную память SC, задавая всем её ячейкам нулевые значения
/// \return 0
int sc_memoryInit()
{
sc_instructionCounter = 0 ;
for (unsigned short & mem : sc_memory)
mem = 0 ;
return 0 ;
}
/// Задает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySet(unsigned short int address, unsigned short int value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_memory[address] = value ;
return 0 ;
}
/// Возвращает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryGet(unsigned short int address, unsigned short int * value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
*value = sc_memory[address] ;
return 0 ;
}
/// Сохраняет содержимое памяти в файл в бинарном виде
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySave(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "wb"))){
return -1 ;
}
fwrite(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Загружает из указанного файла содержимое оперативной памяти
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryLoad(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "rb"))){
return -1 ;
}
fread(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Инициализирует регистр флагов нулевым значением
/// \return 0
int sc_regInit(){
sc_regFLAGS = 0 ;
return 0 ;
}
/// Устанавливает значение указанного регистра флагов
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regSet(int8_t reg, bool value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
value == 1 ? (sc_regFLAGS |= (1 << reg)) : (sc_regFLAGS &=
(1 << reg)) ;
return 0 ;
}
/// Возвращает значение указанного флага
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regGet(int8_t reg, bool *value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
*value = sc_regFLAGS & (1 << reg) ;
return 0 ;
}
/// Кодирует команду с указанным номером и операндом и помещает результат в value
/// \param command - команда
/// \param operand - операнд
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandEncode(unsigned short int command, unsigned short int operand, unsigned short int * value){
if (command > 0x7F)
return -1 ;
if (operand > 0x7F)
return -1 ;
* value = 0 ;
/* Операнд */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (operand >> i) & 1 ;
*value |= (bit << i) ;
}
/* Команда */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (command >> i) & 1 ;
*value |= (bit << (i + 7)) ;
}
return 0 ;
}
/// Декодирует значение как команду SС
/// \param value - значение
/// \param command - команда
/// \param operand - операнд
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandDecode(unsigned short int value, unsigned short int * command, unsigned short int * operand){
int tmpCom = 0, tmpOp = 0 ;
if ((value >> 14) & 1){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> i) & 1 ;
tmpOp |= (bit << i) ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> (i + 7)) & 1 ;
tmpCom |= (bit << i) ;
}
* command = tmpCom ;
* operand = tmpOp ;
return 0 ;
}
myTerm.hpp
#ifndef MYTERM_HPP
#define MYTERM_HPP
#include
#include
enum colors {
RED = 196,
PEACH = 203,
GREEN = 10,
SOFT_GREEN =192,
BLUE = 20,
BLACK = 16,
GRAY = 240,
WHITE = 15,
DEFAULT = 0};
int mt_clrScreen () ;
int mt_gotoXY(unsigned int col,unsigned int row) ;
int mt_getScreenSize(unsigned int *rows, unsigned int* cols) ;
int mt_setFGcolor(enum colors color) ;
int mt_setBGcolor(enum colors color) ;
int mt_setDefaultColorSettings() ;
#endif //MYTERM_HPP
myTerm.cpp
#include "myTerm.hpp"
/// Производит очистку и перемещение курсора в левый верхний угол экрана
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_clrScreen (){
printf("\033[H\033[2J") ;
return 0 ;
}
/// Перемещает курсор в указанную позицию
/// \param col - столбец
/// \param row - строка
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_gotoXY(unsigned int col, unsigned int row)
{
unsigned int rows, cols ;
if (mt_getScreenSize(&rows, &cols) == -1)
return -1 ;
if ((row > rows) || (row <= 0)||(col > cols) || (col <= 0))
return -1 ;
printf("\033[%d;%dH", row, col) ;
return 0 ;
}
/// Определяет размер экрана терминала
/// \param rows - кол-во строк
/// \param cols - кол-во столбцов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_getScreenSize(unsigned int *rows, unsigned int *cols){
winsize ws{} ;
if (ioctl(1, TIOCGWINSZ, &ws))
return -1 ;
* rows = ws.ws_row ;
* cols = ws.ws_col ;
return 0 ;
}
/// Устанавливает цвет последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setFGcolor(enum colors color){
printf("\033[38;5;%dm",color) ;
return 0 ;
}
/// Устанавливает цвет фона последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setBGcolor(enum colors color){
printf("\033[48;5;%dm",color) ;
return 0 ;
}
/// Возвращает цвета в стандартное состояние
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setDefaultColorSettings(){
printf("\033[0m") ;
return 0 ;
}
myUI.hpp
#ifndef MYUI_HPP
#define MYUI_HPP
#include
#include "myBigChars.hpp"
#include "myReadkey.hpp"
#include "simpleComputer.hpp"
int ui_initial() ;
int ui_update() ;
int setCurrMemPointer_to_ICounter() ;
int ui_moveCurrMemPointer(keys key) ;
int ui_setMCellValue() ;
int ui_saveMemory() ;
int ui_loadMemory() ;
int ui_setAccumulator() ;
int ui_setICounter() ;
bool checkCorrectInputHEX(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color);
int clearBuffIn() ;
#endif //MYUI_HPP
myUI.cpp
#include "myUI.hpp"
#include "myReadkey.hpp"
int8_t currMemCell = 0 ;
int drawingBoxes() ;
int drawingTexts() ;
int drawingMemory() ;
int drawingAccumulator() ;
int drawingInstructionCounter() ;
int drawingOperation() ;
int drawingFlags() ;
int drawingBigChar() ;
bool checkCorrectInputHEX(const char *buffer) ;
bool checkCorrectInputDEC(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color) ;
/// "Инициализация" интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_initial(){
currMemCell = 0 ;
if (rk_myTermSave())
return -1 ;
sc_memoryInit() ;
sc_accumulator &= (1 << 14) ;
sc_regInit() ;
sc_regSet(IGNORING_TACT_PULSES, true) ;
return 0 ;
}
/// Обновление интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_update(){
mt_clrScreen() ;
if (drawingBoxes())
return -1 ;
if (drawingTexts())
return -1 ;
if (drawingMemory())
return -1 ;
if (drawingAccumulator())
return -1 ;
if (drawingInstructionCounter())
return -1 ;
if (drawingOperation())
return -1 ;
if (drawingFlags())
return -1 ;
if (drawingBigChar())
return -1 ;
mt_gotoXY(1, 23) ;
printf("Input/Output:\n") ;
return 0 ;
}
/// Перемещение выделенной ячейки на значение ICounter
/// \return 0
int setCurrMemPointer_to_ICounter(){
currMemCell = sc_instructionCounter ;
return 0 ;
}
/// Перемещение выделенной ячейки
/// \param key - Клавиша
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_moveCurrMemPointer(keys key){
switch (key) {
case keys::KEY_UP: (currMemCell <= 9) ? (currMemCell = 90 + currMemCell) : (currMemCell -= 10) ; return 0 ;
case keys::KEY_RIGHT: (!((currMemCell + 1) % 10)) ? (currMemCell -= 9) : (currMemCell += 1) ; return 0 ;
case keys::KEY_DOWN: (currMemCell >= 90) ? (currMemCell = currMemCell - 90) : (currMemCell += 10) ; return 0 ;
case keys::KEY_LEFT: (!(currMemCell % 10)) ? (currMemCell += 9) : (currMemCell -= 1) ; return 0 ;
}
return -1 ;
}
int ui_setMCellValue(){
printf("Set the value of the cell under the number \033[38;5;%dm0x%02X\033[0m\n", colors::SOFT_GREEN, currMemCell) ;
printf("Enter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+')
i = 1 ;
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
if (sc_memorySet(currMemCell, res))
return -1 ;
return 0 ;
}
int ui_saveMemory(){
char filename[102] ;
printf("Saving file...\n") ;
printf("Enter the file name to save > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
printf("\033[38;5;%dmThe file name is too long. The length is trimmed to the first 100 characters.\033[0m\n", BLUE) ;
clearBuffIn(); // очистка потока ввода
}
else
filename[strlen(filename) - 1] = '\0' ;
if (sc_memorySave(filename)){
ui_messageOutput((char *)"Failed to save memory", colors::RED) ;
return -1 ;
}
else
ui_messageOutput((char *)"Successful save", colors::GREEN) ;
return 0 ;
}
int ui_loadMemory(){
char filename[102] ;
printf("Loading file...\n") ;
printf("Enter the file name to load > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
ui_messageOutput((char *)"The name of the file to open is too long (up to 100 characters are allowed)", colors::BLUE) ;
clearBuffIn(); // очистка потока ввода
return -1 ;
}
filename[strlen(filename) - 1] = '\0' ;
if (sc_memoryLoad(filename)){
ui_messageOutput((char *)"Failed to load memory", colors::RED) ;
return -1 ;
}
return 0 ;
}
int ui_setAccumulator(){
// может ли в accumulator храниться команда ? (теперь нет)
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"Accumulator\"\033[0m", colors::GREEN) ;
printf("\nEnter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+'){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if(number > 0x3FFF){
ui_messageOutput((char *)"The command value must not exceed 14 bits (0x3FFF)", colors::RED) ;
return -1 ;
}
else
{
number &= 0x3FFF ;
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
else{
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
}
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
sc_accumulator = res ;
return 0 ;
}
int ui_setICounter(){
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"InstructionCounter\"\033[0m between \033[38;5;%dm00\033[0m and \033[38;5;%dm99\033[0m inclusive\n", colors::GREEN, colors::SOFT_GREEN, colors::SOFT_GREEN) ;
printf("Enter value in \033[38;5;%dmDEC\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
if (!checkCorrectInputDEC(buffer)){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(buffer, &tmp, 10);
if(number > 99){
ui_messageOutput((char *)"The value must not exceed the amount of memory", colors::RED) ;
return -1 ;
}
sc_instructionCounter = (uint8_t)number ;
return 0 ;
}
/// Отрисовка "боксов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBoxes(){
if (bc_box(1, 1, 61, 12)) // Окно Memory
return -1 ;
if (bc_box(62, 1, 22, 3)) // Окно accumulator
return -1 ;
if (bc_box(62, 4, 22, 3)) // Окно instructionCounter
return -1 ;
if (bc_box(62, 7, 22, 3)) // Окно Operation
return -1 ;
if (bc_box(62, 10, 22, 3)) // Окно Flags
return -1 ;
if (bc_box(1, 13, 52, 10)) // Окно BigChars
return -1 ;
if (bc_box(53, 13, 31, 10)) // Окно Keys
return -1 ;
return 0 ;
}
/// Отрисовка заголовков и текста
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingTexts(){
/* Заголовки */
mt_gotoXY(30,1) ;
printf(" Memory ") ;
mt_gotoXY(66,1) ;
printf(" accumulator ") ;
mt_gotoXY(63,4) ;
printf(" instructionCounter ") ;
mt_gotoXY(67,7) ;
printf(" Operation ") ;
mt_gotoXY(69,10) ;
printf(" Flags ") ;
mt_gotoXY(54,13) ;
printf(" Keys: ") ;
/* HotKeys */
char* hotK[] = {(char *)"l - load",
(char *)"s - save",
(char *)"r - run",
(char *)"t - step",
(char *)"i - reset",
(char *)"F5 - accumulator",
(char *)"F6 - instructionCounter"};
for (int i = 0 ; i < sizeof(hotK) / sizeof(*hotK) ; ++i) {
mt_gotoXY(54,i + 14) ;
printf("%s", hotK[i]) ;
}
return 0 ;
}
/// Отрисовка памяти
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingMemory(){
for (int i = 0 ; i < 10 ; ++i)
for (int j = 0 ; j < 10 ; ++j) {
mt_gotoXY(2 + (5 * j + j), 2 + i) ;
unsigned short int tmp ;
sc_memoryGet(i * 10 + j, &tmp) ;
if ((i * 10 + j) == currMemCell)
mt_setBGcolor(colors::GREEN) ;
if((tmp >> 14) & 1)
if((tmp >> 13) & 1)
printf("-%04X", (
(tmp - 1)) & 0x3FFF) ;
else
printf(" %04X", tmp & 0x1FFF) ;
else
printf("+%04X", tmp) ;
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка accumulator
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingAccumulator(){
mt_gotoXY(70,2) ;
// bool over ;
// sc_regGet(OVERFLOW, &over) ;
// if (over){
// mt_setFGcolor(colors::PEACH) ;
// printf(" over") ;
// mt_setDefaultColorSettings() ;
// }
// else{
if((sc_accumulator >> 14) & 1)
if((sc_accumulator >> 13) & 1)
printf("-%04X", (
(sc_accumulator - 1)) & 0x3FFF) ;
else
printf(" %04X", sc_accumulator & 0x1FFF) ;
else
printf("+%04X", sc_accumulator) ;
// }
return 0 ;
}
/// Отрисовка Operation
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingOperation(){
mt_gotoXY(69,8) ;
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1)){
unsigned short int operand, command ;
sc_commandDecode(tmp, &command, &operand) ;
printf("+%02X:%02X", command, operand) ;
}
else{
unsigned short int left, right ;
bool negative = (tmp >> 13) & 1 ;
if(negative)
tmp = (
(tmp - 1)) & 0x3FFF ;
else
tmp &= 0x1FFF ;
left = tmp >> 8 ;
right = tmp & 0xFF ;
negative ? printf("-%02X:%02X", left, right) : printf(" %02X:%02X", left, right) ;
}
return 0 ;
}
/// Отрисовка instructionCounter
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingInstructionCounter(){
mt_gotoXY(71,5) ;
// bool over, zero, out, comm ;
// sc_regGet(OVERFLOW, &over) ;
// sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
// sc_regGet(OUT_OF_MEMORY, &out) ;
// sc_regGet(INCORRECT_COMMAND, &comm) ;
// mt_gotoXY(71,5) ;
// if (over || zero || out || comm){
// mt_setFGcolor(colors::SOFT_GREEN) ;
// printf("null") ;
// mt_setDefaultColorSettings() ;
// }
// else
printf("%04X", sc_instructionCounter) ;
return 0 ;
}
/// Отрисовка флагов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingFlags(){
char tmp[] = {'O', 'Z', 'M', 'I', 'C'};
for (int i = 0 ; i < SC_REG_SIZE ; ++i) {
bool value ;
if (sc_regGet(i, &value))
return -1 ;
mt_gotoXY(68 + (i * 2), 11) ;
if (value){
mt_setFGcolor(colors::PEACH) ;
printf("%c", tmp[i]) ;
}
else{
mt_setFGcolor(colors::GRAY) ;
printf("%c", tmp[i]) ;
}
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка "BigChar'ов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBigChar(){
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1))
bc_printBigChar(bc[16], 2, 14, GREEN) ;
else if((tmp >> 13) & 1){
bc_printBigChar(bc[17], 2, 14, GREEN) ;
tmp = (
(tmp - 1)) & 0x3FFF;
}
else
tmp &= 0x3FFF ;
for (int i = 0; i < 4; ++i) {
int ch = (tmp & ( 0xF << (4 * (3 - i)) )) >> (4 * (3 - i)) ;
bc_printBigChar(bc[ch], 2 + 8 * (i + 1) + 2 * (i + 1), 14, GREEN) ;
}
return 0 ;
}
bool checkCorrectInputHEX(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 4)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isxdigit(buffer[i])))
return false ;
return true ;
}
bool checkCorrectInputDEC(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 5)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isdigit(buffer[i])))
return false ;
return true ;
}
int ui_messageOutput(char *str, enum colors color){
printf("\033[38;5;%dm%s\033[0m", color, str) ;
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
return 0 ;
}
int clearBuffIn(){
int c;
do {
c = getchar();
} while (c != '\n' && c != '\0');
return 0 ;
}
myReadkey.hpp
#ifndef MYREADKEY_HPP
#define MYREADKEY_HPP
#include
#include
#include
extern termios save;
enum keys
{
KEY_L,
KEY_S,
KEY_R,
KEY_T,
KEY_I,
KEY_F5,
KEY_F6 ,
KEY_UP,
KEY_DOWN,
KEY_RIGHT,
KEY_LEFT,
KEY_ESC,
KEY_ENTER,
KEY_OTHER,
};
int rk_readKey(enum keys *key) ;
int rk_myTermSave() ;
int rk_myTermRestore() ;
int rk_myTermRegime (bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint) ;
#endif //MYREADKEY_HPP
myReadkey.cpp
#include "myReadkey.hpp"
termios save;
/// Возвращающую первую клавишу, которую нажал пользователь
/// \param key - Адрес переменной, в которую возвращается номер нажатой клавиши
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_readKey (enum keys * key){
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
rk_myTermRestore() ;
if (buffer[0] == '\033')
if (buffer[1] == '\0')
*key = KEY_ESC ;
else if (buffer[1] == '[')
if (buffer[2] == 'A' and buffer[3] == '\0')
*key = KEY_UP ;
else if (buffer[2] == 'B' and buffer[3] == '\0')
*key = KEY_DOWN ;
else if (buffer[2] == 'C' and buffer[3] == '\0')
*key = KEY_RIGHT ;
else if (buffer[2] == 'D' and buffer[3] == '\0')
*key = KEY_LEFT ;
else if (buffer[2] == '1' and buffer[3] == '5')
*key = KEY_F5 ;
else if (buffer[2] == '1' and buffer[3] == '7')
*key = KEY_F6 ;
else
*key = KEY_OTHER ;
else
*key = KEY_OTHER ;
else if (buffer[0] == '\n' and buffer[1] == '\0')
*key = KEY_ENTER ;
else
if ((buffer[0] == 'l' or buffer[0] == 'L') and buffer[1] == '\0')
*key = KEY_L ;
else if ((buffer[0] == 's' or buffer[0] == 'S') and buffer[1] == '\0')
*key = KEY_S ;
else if ((buffer[0] == 'r' or buffer[0] == 'R') and buffer[1] == '\0')
*key = KEY_R ;
else if ((buffer[0] == 't' or buffer[0] == 'T') and buffer[1] == '\0')
*key = KEY_T ;
else if ((buffer[0] == 'i' or buffer[0] == 'I') and buffer[1] == '\0')
*key = KEY_I ;
else
*key = KEY_OTHER ;
return 0 ;
}
/// Функция, сохраняющая текущие параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermSave(){
if (tcgetattr(fileno(stdin), &save))
return -1 ;
return 0 ;
}
/// Функция, восстанавливающая сохраненные параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRestore(){
tcsetattr(fileno(stdin), TCSAFLUSH, &save) ;
return 0 ;
}
/// Функция, переключающая режим работы терминала (канонический / неканонический)
/// \param regime
/// \param vtime
/// \param vmin
/// \param echo
/// \param sigint
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRegime(bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint){
termios curr{} ;
tcgetattr(fileno(stdin), &curr) ;
if(regime)
curr.c_lflag |= ICANON ;
else{
curr.c_lflag &=
ICANON ;
sigint ? (curr.c_lflag |= ISIG) : (curr.c_lflag &=
ISIG) ;
echo ? (curr.c_lflag |= ECHO) : (curr.c_lflag &=
ECHO) ;
curr.c_cc[VMIN] = vmin ;
curr.c_cc[VTIME] = vtime ;
}
tcsetattr(0,TCSAFLUSH,&curr) ;
return 0 ;
}
commands.hpp
#ifndef COMMANDS_HPP
#define COMMANDS_HPP
#define READ 0x10
#define WRITE 0x11
#define LOAD 0x20
#define STORE 0x21
#define ADD 0x30
#define SUB 0x31
#define DIVIDE 0x32
#define MUL 0x33
#define JUMP 0x40
#define JNEG 0x41
#define JZ 0x42
#define HALT 0x43
#define RCR 0x63
#endif //COMMANDS_HPP
myCU.hpp
#ifndef CU_HPP
#define CU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
#include "myALU.hpp"
int CU() ;
#endif //CU_HPP
myCU.cpp
#include "myCU.hpp"
int cu_read(unsigned short int operand) ;
int cu_write(unsigned short int operand) ;
int cu_load(unsigned short int operand) ;
int cu_store(unsigned short int operand) ;
int cu_jump(unsigned short int operand) ;
int cu_jneg(unsigned short int operand) ;
int cu_jz(unsigned short int operand) ;
int CU (){
unsigned short int command = 0;
unsigned short int operand = 0;
unsigned short int currCell;
sc_memoryGet(sc_instructionCounter, &currCell) ;
if (sc_commandDecode(currCell, &command, &operand)){
return -1 ;
}
switch (command) {
case READ:
if (cu_read(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case WRITE:
if (cu_write(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case LOAD :
if (cu_load(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case STORE :
if (cu_store(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case JUMP :
if (cu_jump(operand))
return -1 ;
break ;
case JNEG :
if (cu_jneg(operand))
return -1 ;
break ;
case JZ :
if (cu_jz(operand))
return -1 ;
break ;
case HALT :
return -1 ;
break ;
default:
if (ALU(command, operand))
return -1 ;
break ;
}
return 0 ;
}
int cu_read(unsigned short int operand){
rk_myTermRestore() ;
printf("Enter value of cell[\033[38;5;%dm0x%02X\033[0m] in \033[38;5;%dmHEX\033[0m format > ", colors::SOFT_GREEN, operand, colors::PEACH) ;
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
rk_myTermRegime(false, 0, 0, false, false) ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+' or buffer[0] == '-')
i = 1 ;
else{
res |= (1 << 14) ;
(buffer[0] == '-') ? (res |= (1 << 13)) : i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
res |= (1 << 15) ;
}
else{
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if (number > 0x3FFF)
res |= (1 << 15) ;
else
{
number &= 0x3FFF ;
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value)){
res |= (1 << 15) ;
}
else
res |= value ;
}
}
else{
if (number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
res |= (1 << 15) ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
}
if (sc_memorySet(operand, (unsigned short int)res))
return -1 ;
return 0 ;
}
int cu_write(unsigned short int operand){
unsigned short int value;
if(sc_memoryGet(operand, &value)){
return -1 ;
}
printf("Value in a cell [\033[38;5;%dm0x%02X\033[0m] < ", colors::SOFT_GREEN, operand) ;
if ((value >> 14) & 1)
if ((value >> 13) & 1)
printf("-%04X", (
(value - 1)) & 0x3FFF) ;
else
printf(" %04X", value & 0x1FFF) ;
else
printf("+%04X", value) ;
getchar() ;
return 0 ;
}
int cu_load(unsigned short int operand){
unsigned short int value;
if (sc_memoryGet(operand, &value)){
return -1 ;
}
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return - 1;
}
sc_accumulator = value ;
return 0 ;
}
int cu_store(unsigned short int operand){
if (sc_memorySet(operand, sc_accumulator))
return -1 ;
return 0 ;
}
int cu_jump(unsigned short int operand){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
return 0 ;
}
int cu_jneg(unsigned short int operand){
if (((sc_accumulator >> 14) & 1) and ((sc_accumulator >> 13) & 1)){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
}
else
sc_instructionCounter++ ;
return 0 ;
}
int cu_jz(unsigned short int operand){
if (((sc_accumulator >> 14) & 1) and ((sc_accumulator & 0x3FFF) == 0)){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
}
else
sc_instructionCounter++ ;
return 0 ;
}
myALU.hpp
#ifndef MYALU_HPP
#define MYALU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
int ALU(unsigned short int command, unsigned short int operand) ;
#endif //MYALU_HPP
myALU.cpp
#include "myALU.hpp"
int alu_add(unsigned short int value) ;
int alu_divide(unsigned short int operand) ;
int alu_mul(unsigned short int operand) ;
int alu_rcr(unsigned short int operand) ;
int ALU(unsigned short int command, unsigned short int operand){
unsigned short int value ;
switch (command) {
case ADD:
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
if (alu_add(value))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case SUB:
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
if ((value >> 13) & 1) // Отрицательное
value =
((value & 0x3FFF) - 1) ;
else
value = (
(value & 0x3FFF)) + 1 ;
value &= 0x3FFF ;
value |= (1 << 14) ;
if (alu_add(value))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case DIVIDE:
if (alu_divide(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case MUL:
if (alu_mul(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case RCR:
if (alu_rcr(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
default:
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
return 0 ;
}
int alu_add(unsigned short int value){
unsigned short int accumulator, res;
accumulator = sc_accumulator & 0x3FFF ;
value &= 0x3FFF;
if (((accumulator >> 13) & 1) and ((value >> 13) & 1)){ // Если оба отрицательны
value =
(value - 1) & 0x3FFF ;
accumulator =
(accumulator - 1) & 0x3FFF ;
res = accumulator + value;
if (res > 0x2000){
sc_regSet(OVERFLOW, true) ;
}
res =
res + 1 ;
Приложение. Листинг
Makefile
d.PHONY: all clean run
COMPILER := g++
FLAGS := -fdiagnostics-color=always -Werror -MMD
SRC_SC := src/sc
BUILD_SC := build/sc
LIBS_SC := libs/sc
SRC_SA := src/sa
BUILD_SA := build/sa
SRC_SB := src/sb
BUILD_SB := build/sb
BIN := bin
SC := simpleComputer
SA := simpleAssembler
SB := simpleBasic
all: create $(BIN)/$(SC) $(BIN)/$(SA) $(BIN)/$(SB)
-include $((BUILD_SC)/*.d
-include $((BUILD_SA)/*.d
-include $((BUILD_SB)/*.d
sc: create $(BIN)/$(SC)
run_sc: sc
./$(BIN)/$(SC)
$(BIN)/$(SC): $(LIBS_SC)/libsimpleComputer.a $(LIBS_SC)/libmyTerm.a $(LIBS_SC)/libmyBigChars.a $(LIBS_SC)/libmyReadkey.a $(LIBS_SC)/libmyUI.a $(LIBS_SC)/libmyALU.a $(LIBS_SC)/libmyCU.a $(BUILD_SC)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SC) $(BUILD_SC)/main.o -L $(LIBS_SC) -lsimpleComputer -lmyUI -lmyTerm -lmyBigChars -lmyReadkey -lmyCU -lmyALU
$(BUILD_SC)/%.o: $(SRC_SC)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
$(LIBS_SC)/libsimpleComputer.a: $(BUILD_SC)/simpleComputer.o
ar cr $@ $^
$(LIBS_SC)/libmyTerm.a: $(BUILD_SC)/myTerm.o
ar cr $@ $^
$(LIBS_SC)/libmyBigChars.a: $(BUILD_SC)/myBigChars.o
ar cr $@ $^
$(LIBS_SC)/libmyReadkey.a: $(BUILD_SC)/myReadkey.o
ar cr $@ $^
$(LIBS_SC)/libmyUI.a: $(BUILD_SC)/myUI.o
ar cr $@ $^
$(LIBS_SC)/libmyALU.a: $(BUILD_SC)/myALU.o
ar cr $@ $^
$(LIBS_SC)/libmyCU.a: $(BUILD_SC)/myCU.o
ar cr $@ $^
sa: create $(BIN)/$(SA)
run_sa: create $(BIN)/$(SA)
./$(BIN)/$(SA)
$(BIN)/$(SA): $(BUILD_SA)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SA) $(BUILD_SA)/main.o
$(BUILD_SA)/%.o: $(SRC_SA)/%.cpps
$(COMPILER) $(FLAGS) -c $^ -o $@
sb: create $(BIN)/$(SB)
run_sb: create $(BIN)/$(SB)
./$(BIN)/$(SB)
$(BIN)/$(SB): $(BUILD_SB)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SB) $(BUILD_SB)/main.o
$(BUILD_SB)/%.o: $(SRC_SB)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
create:
mkdir -p $(BUILD_SC) $(BUILD_SA) $(BUILD_SB) $(LIBS_SC) $(BIN)
clean:
@rm -rf build libs $(BIN)
SimpleComputer
main.cpp
#include
#include "simpleComputer.hpp"
#include "myUI.hpp"
#include "myReadkey.hpp"
#include "myCU.hpp"
void signalHandler(int signal) ;
#include
int main(int argc, char const *argv[]){
ui_initial() ;
signal(SIGALRM, signalHandler) ;
signal(SIGUSR1, signalHandler) ;
bool zero, out, ignor, comm ;
keys key;
if (argc == 2){
sc_memoryLoad((char *)argv[1]) ;
}
else if (argc > 2){
ui_messageOutput((char *)"Exceeded the number of arguments", colors::RED) ;
return -1 ;
}
do {
sc_regGet(IGNORING_TACT_PULSES, &ignor);
ui_update() ;
rk_readKey(&key);
if (ignor){
sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
sc_regGet(OUT_OF_MEMORY, &out) ;
sc_regGet(INCORRECT_COMMAND, &comm) ;
if (zero || out || comm){
switch(key){
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
}
}
else{
switch(key){
case keys::KEY_UP:
ui_moveCurrMemPointer(keys::KEY_UP) ;
break ;
case keys::KEY_RIGHT:
ui_moveCurrMemPointer(keys::KEY_RIGHT) ;
break ;
case keys::KEY_DOWN:
ui_moveCurrMemPointer(keys::KEY_DOWN) ;
break ;
case keys::KEY_LEFT:
ui_moveCurrMemPointer(keys::KEY_LEFT) ;
break ;
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_R:
sc_regInit() ;
raise(SIGALRM) ;
break ;
case keys::KEY_T:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
CU() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
case keys::KEY_F5:
ui_setAccumulator() ;
break ;
case keys::KEY_F6:
ui_setICounter() ;
break ;
case keys::KEY_ENTER:
ui_setMCellValue() ;
break ;
}
}
}
else
if (key == keys::KEY_I)
raise(SIGUSR1) ;
} while(key != keys::KEY_ESC) ;
return 0 ;
}
void signalHandler(int signal){
switch (signal) {
case SIGALRM:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
if (CU()){
sc_regSet(IGNORING_TACT_PULSES, true);
ui_update() ;
alarm(0) ;
}
else
alarm(1) ;
rk_myTermRegime(false, 0, 0, false, false) ;
break ;
case SIGUSR1:
alarm(0) ;
ui_initial() ;
break ;
default:
break ;
}
}
simpleComputer.hpp
#ifndef SIMPLECOMPUTER_HPP
#define SIMPLECOMPUTER_HPP
#include
#define OVERFLOW 0 // Переполнение при выполнении операции
#define DIVISION_ERR_BY_ZERO 1 // Ошибка деления на 0
#define OUT_OF_MEMORY 2 // Ошибка выхода за границы памяти
#define IGNORING_TACT_PULSES 3 // Игнорирование тактовых импульсов
#define INCORRECT_COMMAND 4 // Указана неверная команда
const short int SC_REG_SIZE = 5 ;
const short int SC_MEM_SIZE = 100 ;
extern unsigned short int sc_accumulator ;
extern uint8_t sc_instructionCounter ;
int sc_memoryInit () ;
int sc_memorySet (unsigned short int address, unsigned short int value) ;
int sc_memoryGet (unsigned short int address, unsigned short int * value) ;
int sc_memorySave (char* filename) ;
int sc_memoryLoad (char* filename) ;
int sc_regInit () ;
int sc_regSet (int8_t reg, bool value) ;
int sc_regGet (int8_t reg, bool * value) ;
int sc_commandEncode (unsigned short int command, unsigned short int operand, unsigned short int * value) ;
int sc_commandDecode (unsigned short int value, unsigned short int * command, unsigned short int * operand) ;
#endif //SIMPLECOMPUTER_HPP
simpleComputer.cpp
#include "simpleComputer.hpp"
unsigned short int sc_memory[SC_MEM_SIZE] ;
uint8_t sc_regFLAGS ;
unsigned short int sc_accumulator ;
uint8_t sc_instructionCounter ;
/// Инициализирует оперативную память SC, задавая всем её ячейкам нулевые значения
/// \return 0
int sc_memoryInit()
{
sc_instructionCounter = 0 ;
for (unsigned short & mem : sc_memory)
mem = 0 ;
return 0 ;
}
/// Задает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySet(unsigned short int address, unsigned short int value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_memory[address] = value ;
return 0 ;
}
/// Возвращает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryGet(unsigned short int address, unsigned short int * value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
*value = sc_memory[address] ;
return 0 ;
}
/// Сохраняет содержимое памяти в файл в бинарном виде
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySave(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "wb"))){
return -1 ;
}
fwrite(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Загружает из указанного файла содержимое оперативной памяти
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryLoad(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "rb"))){
return -1 ;
}
fread(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Инициализирует регистр флагов нулевым значением
/// \return 0
int sc_regInit(){
sc_regFLAGS = 0 ;
return 0 ;
}
/// Устанавливает значение указанного регистра флагов
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regSet(int8_t reg, bool value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
value == 1 ? (sc_regFLAGS |= (1 << reg)) : (sc_regFLAGS &=
(1 << reg)) ;
return 0 ;
}
/// Возвращает значение указанного флага
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regGet(int8_t reg, bool *value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
*value = sc_regFLAGS & (1 << reg) ;
return 0 ;
}
/// Кодирует команду с указанным номером и операндом и помещает результат в value
/// \param command - команда
/// \param operand - операнд
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandEncode(unsigned short int command, unsigned short int operand, unsigned short int * value){
if (command > 0x7F)
return -1 ;
if (operand > 0x7F)
return -1 ;
* value = 0 ;
/* Операнд */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (operand >> i) & 1 ;
*value |= (bit << i) ;
}
/* Команда */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (command >> i) & 1 ;
*value |= (bit << (i + 7)) ;
}
return 0 ;
}
/// Декодирует значение как команду SС
/// \param value - значение
/// \param command - команда
/// \param operand - операнд
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandDecode(unsigned short int value, unsigned short int * command, unsigned short int * operand){
int tmpCom = 0, tmpOp = 0 ;
if ((value >> 14) & 1){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> i) & 1 ;
tmpOp |= (bit << i) ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> (i + 7)) & 1 ;
tmpCom |= (bit << i) ;
}
* command = tmpCom ;
* operand = tmpOp ;
return 0 ;
}
myTerm.hpp
#ifndef MYTERM_HPP
#define MYTERM_HPP
#include
#include
enum colors {
RED = 196,
PEACH = 203,
GREEN = 10,
SOFT_GREEN =192,
BLUE = 20,
BLACK = 16,
GRAY = 240,
WHITE = 15,
DEFAULT = 0};
int mt_clrScreen () ;
int mt_gotoXY(unsigned int col,unsigned int row) ;
int mt_getScreenSize(unsigned int *rows, unsigned int* cols) ;
int mt_setFGcolor(enum colors color) ;
int mt_setBGcolor(enum colors color) ;
int mt_setDefaultColorSettings() ;
#endif //MYTERM_HPP
myTerm.cpp
#include "myTerm.hpp"
/// Производит очистку и перемещение курсора в левый верхний угол экрана
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_clrScreen (){
printf("\033[H\033[2J") ;
return 0 ;
}
/// Перемещает курсор в указанную позицию
/// \param col - столбец
/// \param row - строка
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_gotoXY(unsigned int col, unsigned int row)
{
unsigned int rows, cols ;
if (mt_getScreenSize(&rows, &cols) == -1)
return -1 ;
if ((row > rows) || (row <= 0)||(col > cols) || (col <= 0))
return -1 ;
printf("\033[%d;%dH", row, col) ;
return 0 ;
}
/// Определяет размер экрана терминала
/// \param rows - кол-во строк
/// \param cols - кол-во столбцов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_getScreenSize(unsigned int *rows, unsigned int *cols){
winsize ws{} ;
if (ioctl(1, TIOCGWINSZ, &ws))
return -1 ;
* rows = ws.ws_row ;
* cols = ws.ws_col ;
return 0 ;
}
/// Устанавливает цвет последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setFGcolor(enum colors color){
printf("\033[38;5;%dm",color) ;
return 0 ;
}
/// Устанавливает цвет фона последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setBGcolor(enum colors color){
printf("\033[48;5;%dm",color) ;
return 0 ;
}
/// Возвращает цвета в стандартное состояние
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setDefaultColorSettings(){
printf("\033[0m") ;
return 0 ;
}
myUI.hpp
#ifndef MYUI_HPP
#define MYUI_HPP
#include
#include "myBigChars.hpp"
#include "myReadkey.hpp"
#include "simpleComputer.hpp"
int ui_initial() ;
int ui_update() ;
int setCurrMemPointer_to_ICounter() ;
int ui_moveCurrMemPointer(keys key) ;
int ui_setMCellValue() ;
int ui_saveMemory() ;
int ui_loadMemory() ;
int ui_setAccumulator() ;
int ui_setICounter() ;
bool checkCorrectInputHEX(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color);
int clearBuffIn() ;
#endif //MYUI_HPP
myUI.cpp
#include "myUI.hpp"
#include "myReadkey.hpp"
int8_t currMemCell = 0 ;
int drawingBoxes() ;
int drawingTexts() ;
int drawingMemory() ;
int drawingAccumulator() ;
int drawingInstructionCounter() ;
int drawingOperation() ;
int drawingFlags() ;
int drawingBigChar() ;
bool checkCorrectInputHEX(const char *buffer) ;
bool checkCorrectInputDEC(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color) ;
/// "Инициализация" интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_initial(){
currMemCell = 0 ;
if (rk_myTermSave())
return -1 ;
sc_memoryInit() ;
sc_accumulator &= (1 << 14) ;
sc_regInit() ;
sc_regSet(IGNORING_TACT_PULSES, true) ;
return 0 ;
}
/// Обновление интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_update(){
mt_clrScreen() ;
if (drawingBoxes())
return -1 ;
if (drawingTexts())
return -1 ;
if (drawingMemory())
return -1 ;
if (drawingAccumulator())
return -1 ;
if (drawingInstructionCounter())
return -1 ;
if (drawingOperation())
return -1 ;
if (drawingFlags())
return -1 ;
if (drawingBigChar())
return -1 ;
mt_gotoXY(1, 23) ;
printf("Input/Output:\n") ;
return 0 ;
}
/// Перемещение выделенной ячейки на значение ICounter
/// \return 0
int setCurrMemPointer_to_ICounter(){
currMemCell = sc_instructionCounter ;
return 0 ;
}
/// Перемещение выделенной ячейки
/// \param key - Клавиша
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_moveCurrMemPointer(keys key){
switch (key) {
case keys::KEY_UP: (currMemCell <= 9) ? (currMemCell = 90 + currMemCell) : (currMemCell -= 10) ; return 0 ;
case keys::KEY_RIGHT: (!((currMemCell + 1) % 10)) ? (currMemCell -= 9) : (currMemCell += 1) ; return 0 ;
case keys::KEY_DOWN: (currMemCell >= 90) ? (currMemCell = currMemCell - 90) : (currMemCell += 10) ; return 0 ;
case keys::KEY_LEFT: (!(currMemCell % 10)) ? (currMemCell += 9) : (currMemCell -= 1) ; return 0 ;
}
return -1 ;
}
int ui_setMCellValue(){
printf("Set the value of the cell under the number \033[38;5;%dm0x%02X\033[0m\n", colors::SOFT_GREEN, currMemCell) ;
printf("Enter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+')
i = 1 ;
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
if (sc_memorySet(currMemCell, res))
return -1 ;
return 0 ;
}
int ui_saveMemory(){
char filename[102] ;
printf("Saving file...\n") ;
printf("Enter the file name to save > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
printf("\033[38;5;%dmThe file name is too long. The length is trimmed to the first 100 characters.\033[0m\n", BLUE) ;
clearBuffIn(); // очистка потока ввода
}
else
filename[strlen(filename) - 1] = '\0' ;
if (sc_memorySave(filename)){
ui_messageOutput((char *)"Failed to save memory", colors::RED) ;
return -1 ;
}
else
ui_messageOutput((char *)"Successful save", colors::GREEN) ;
return 0 ;
}
int ui_loadMemory(){
char filename[102] ;
printf("Loading file...\n") ;
printf("Enter the file name to load > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
ui_messageOutput((char *)"The name of the file to open is too long (up to 100 characters are allowed)", colors::BLUE) ;
clearBuffIn(); // очистка потока ввода
return -1 ;
}
filename[strlen(filename) - 1] = '\0' ;
if (sc_memoryLoad(filename)){
ui_messageOutput((char *)"Failed to load memory", colors::RED) ;
return -1 ;
}
return 0 ;
}
int ui_setAccumulator(){
// может ли в accumulator храниться команда ? (теперь нет)
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"Accumulator\"\033[0m", colors::GREEN) ;
printf("\nEnter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+'){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if(number > 0x3FFF){
ui_messageOutput((char *)"The command value must not exceed 14 bits (0x3FFF)", colors::RED) ;
return -1 ;
}
else
{
number &= 0x3FFF ;
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
else{
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
}
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
sc_accumulator = res ;
return 0 ;
}
int ui_setICounter(){
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"InstructionCounter\"\033[0m between \033[38;5;%dm00\033[0m and \033[38;5;%dm99\033[0m inclusive\n", colors::GREEN, colors::SOFT_GREEN, colors::SOFT_GREEN) ;
printf("Enter value in \033[38;5;%dmDEC\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
if (!checkCorrectInputDEC(buffer)){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(buffer, &tmp, 10);
if(number > 99){
ui_messageOutput((char *)"The value must not exceed the amount of memory", colors::RED) ;
return -1 ;
}
sc_instructionCounter = (uint8_t)number ;
return 0 ;
}
/// Отрисовка "боксов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBoxes(){
if (bc_box(1, 1, 61, 12)) // Окно Memory
return -1 ;
if (bc_box(62, 1, 22, 3)) // Окно accumulator
return -1 ;
if (bc_box(62, 4, 22, 3)) // Окно instructionCounter
return -1 ;
if (bc_box(62, 7, 22, 3)) // Окно Operation
return -1 ;
if (bc_box(62, 10, 22, 3)) // Окно Flags
return -1 ;
if (bc_box(1, 13, 52, 10)) // Окно BigChars
return -1 ;
if (bc_box(53, 13, 31, 10)) // Окно Keys
return -1 ;
return 0 ;
}
/// Отрисовка заголовков и текста
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingTexts(){
/* Заголовки */
mt_gotoXY(30,1) ;
printf(" Memory ") ;
mt_gotoXY(66,1) ;
printf(" accumulator ") ;
mt_gotoXY(63,4) ;
printf(" instructionCounter ") ;
mt_gotoXY(67,7) ;
printf(" Operation ") ;
mt_gotoXY(69,10) ;
printf(" Flags ") ;
mt_gotoXY(54,13) ;
printf(" Keys: ") ;
/* HotKeys */
char* hotK[] = {(char *)"l - load",
(char *)"s - save",
(char *)"r - run",
(char *)"t - step",
(char *)"i - reset",
(char *)"F5 - accumulator",
(char *)"F6 - instructionCounter"};
for (int i = 0 ; i < sizeof(hotK) / sizeof(*hotK) ; ++i) {
mt_gotoXY(54,i + 14) ;
printf("%s", hotK[i]) ;
}
return 0 ;
}
/// Отрисовка памяти
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingMemory(){
for (int i = 0 ; i < 10 ; ++i)
for (int j = 0 ; j < 10 ; ++j) {
mt_gotoXY(2 + (5 * j + j), 2 + i) ;
unsigned short int tmp ;
sc_memoryGet(i * 10 + j, &tmp) ;
if ((i * 10 + j) == currMemCell)
mt_setBGcolor(colors::GREEN) ;
if((tmp >> 14) & 1)
if((tmp >> 13) & 1)
printf("-%04X", (
(tmp - 1)) & 0x3FFF) ;
else
printf(" %04X", tmp & 0x1FFF) ;
else
printf("+%04X", tmp) ;
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка accumulator
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingAccumulator(){
mt_gotoXY(70,2) ;
// bool over ;
// sc_regGet(OVERFLOW, &over) ;
// if (over){
// mt_setFGcolor(colors::PEACH) ;
// printf(" over") ;
// mt_setDefaultColorSettings() ;
// }
// else{
if((sc_accumulator >> 14) & 1)
if((sc_accumulator >> 13) & 1)
printf("-%04X", (
(sc_accumulator - 1)) & 0x3FFF) ;
else
printf(" %04X", sc_accumulator & 0x1FFF) ;
else
printf("+%04X", sc_accumulator) ;
// }
return 0 ;
}
/// Отрисовка Operation
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingOperation(){
mt_gotoXY(69,8) ;
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1)){
unsigned short int operand, command ;
sc_commandDecode(tmp, &command, &operand) ;
printf("+%02X:%02X", command, operand) ;
}
else{
unsigned short int left, right ;
bool negative = (tmp >> 13) & 1 ;
if(negative)
tmp = (
(tmp - 1)) & 0x3FFF ;
else
tmp &= 0x1FFF ;
left = tmp >> 8 ;
right = tmp & 0xFF ;
negative ? printf("-%02X:%02X", left, right) : printf(" %02X:%02X", left, right) ;
}
return 0 ;
}
/// Отрисовка instructionCounter
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingInstructionCounter(){
mt_gotoXY(71,5) ;
// bool over, zero, out, comm ;
// sc_regGet(OVERFLOW, &over) ;
// sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
// sc_regGet(OUT_OF_MEMORY, &out) ;
// sc_regGet(INCORRECT_COMMAND, &comm) ;
// mt_gotoXY(71,5) ;
// if (over || zero || out || comm){
// mt_setFGcolor(colors::SOFT_GREEN) ;
// printf("null") ;
// mt_setDefaultColorSettings() ;
// }
// else
printf("%04X", sc_instructionCounter) ;
return 0 ;
}
/// Отрисовка флагов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingFlags(){
char tmp[] = {'O', 'Z', 'M', 'I', 'C'};
for (int i = 0 ; i < SC_REG_SIZE ; ++i) {
bool value ;
if (sc_regGet(i, &value))
return -1 ;
mt_gotoXY(68 + (i * 2), 11) ;
if (value){
mt_setFGcolor(colors::PEACH) ;
printf("%c", tmp[i]) ;
}
else{
mt_setFGcolor(colors::GRAY) ;
printf("%c", tmp[i]) ;
}
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка "BigChar'ов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBigChar(){
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1))
bc_printBigChar(bc[16], 2, 14, GREEN) ;
else if((tmp >> 13) & 1){
bc_printBigChar(bc[17], 2, 14, GREEN) ;
tmp = (
(tmp - 1)) & 0x3FFF;
}
else
tmp &= 0x3FFF ;
for (int i = 0; i < 4; ++i) {
int ch = (tmp & ( 0xF << (4 * (3 - i)) )) >> (4 * (3 - i)) ;
bc_printBigChar(bc[ch], 2 + 8 * (i + 1) + 2 * (i + 1), 14, GREEN) ;
}
return 0 ;
}
bool checkCorrectInputHEX(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 4)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isxdigit(buffer[i])))
return false ;
return true ;
}
bool checkCorrectInputDEC(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 5)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isdigit(buffer[i])))
return false ;
return true ;
}
int ui_messageOutput(char *str, enum colors color){
printf("\033[38;5;%dm%s\033[0m", color, str) ;
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
return 0 ;
}
int clearBuffIn(){
int c;
do {
c = getchar();
} while (c != '\n' && c != '\0');
return 0 ;
}
myReadkey.hpp
#ifndef MYREADKEY_HPP
#define MYREADKEY_HPP
#include
#include
#include
extern termios save;
enum keys
{
KEY_L,
KEY_S,
KEY_R,
KEY_T,
KEY_I,
KEY_F5,
KEY_F6 ,
KEY_UP,
KEY_DOWN,
KEY_RIGHT,
KEY_LEFT,
KEY_ESC,
KEY_ENTER,
KEY_OTHER,
};
int rk_readKey(enum keys *key) ;
int rk_myTermSave() ;
int rk_myTermRestore() ;
int rk_myTermRegime (bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint) ;
#endif //MYREADKEY_HPP
myReadkey.cpp
#include "myReadkey.hpp"
termios save;
/// Возвращающую первую клавишу, которую нажал пользователь
/// \param key - Адрес переменной, в которую возвращается номер нажатой клавиши
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_readKey (enum keys * key){
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
rk_myTermRestore() ;
if (buffer[0] == '\033')
if (buffer[1] == '\0')
*key = KEY_ESC ;
else if (buffer[1] == '[')
if (buffer[2] == 'A' and buffer[3] == '\0')
*key = KEY_UP ;
else if (buffer[2] == 'B' and buffer[3] == '\0')
*key = KEY_DOWN ;
else if (buffer[2] == 'C' and buffer[3] == '\0')
*key = KEY_RIGHT ;
else if (buffer[2] == 'D' and buffer[3] == '\0')
*key = KEY_LEFT ;
else if (buffer[2] == '1' and buffer[3] == '5')
*key = KEY_F5 ;
else if (buffer[2] == '1' and buffer[3] == '7')
*key = KEY_F6 ;
else
*key = KEY_OTHER ;
else
*key = KEY_OTHER ;
else if (buffer[0] == '\n' and buffer[1] == '\0')
*key = KEY_ENTER ;
else
if ((buffer[0] == 'l' or buffer[0] == 'L') and buffer[1] == '\0')
*key = KEY_L ;
else if ((buffer[0] == 's' or buffer[0] == 'S') and buffer[1] == '\0')
*key = KEY_S ;
else if ((buffer[0] == 'r' or buffer[0] == 'R') and buffer[1] == '\0')
*key = KEY_R ;
else if ((buffer[0] == 't' or buffer[0] == 'T') and buffer[1] == '\0')
*key = KEY_T ;
else if ((buffer[0] == 'i' or buffer[0] == 'I') and buffer[1] == '\0')
*key = KEY_I ;
else
*key = KEY_OTHER ;
return 0 ;
}
/// Функция, сохраняющая текущие параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermSave(){
if (tcgetattr(fileno(stdin), &save))
return -1 ;
return 0 ;
}
/// Функция, восстанавливающая сохраненные параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRestore(){
tcsetattr(fileno(stdin), TCSAFLUSH, &save) ;
return 0 ;
}
/// Функция, переключающая режим работы терминала (канонический / неканонический)
/// \param regime
/// \param vtime
/// \param vmin
/// \param echo
/// \param sigint
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRegime(bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint){
termios curr{} ;
tcgetattr(fileno(stdin), &curr) ;
if(regime)
curr.c_lflag |= ICANON ;
else{
curr.c_lflag &=
ICANON ;
sigint ? (curr.c_lflag |= ISIG) : (curr.c_lflag &=
ISIG) ;
echo ? (curr.c_lflag |= ECHO) : (curr.c_lflag &=
ECHO) ;
curr.c_cc[VMIN] = vmin ;
curr.c_cc[VTIME] = vtime ;
}
tcsetattr(0,TCSAFLUSH,&curr) ;
return 0 ;
}
commands.hpp
#ifndef COMMANDS_HPP
#define COMMANDS_HPP
#define READ 0x10
#define WRITE 0x11
#define LOAD 0x20
#define STORE 0x21
#define ADD 0x30
#define SUB 0x31
#define DIVIDE 0x32
#define MUL 0x33
#define JUMP 0x40
#define JNEG 0x41
#define JZ 0x42
#define HALT 0x43
#define RCR 0x63
#endif //COMMANDS_HPP
myCU.hpp
#ifndef CU_HPP
#define CU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
#include "myALU.hpp"
int CU() ;
#endif //CU_HPP
myCU.cpp
#include "myCU.hpp"
int cu_read(unsigned short int operand) ;
int cu_write(unsigned short int operand) ;
int cu_load(unsigned short int operand) ;
int cu_store(unsigned short int operand) ;
int cu_jump(unsigned short int operand) ;
int cu_jneg(unsigned short int operand) ;
int cu_jz(unsigned short int operand) ;
int CU (){
unsigned short int command = 0;
unsigned short int operand = 0;
unsigned short int currCell;
sc_memoryGet(sc_instructionCounter, &currCell) ;
if (sc_commandDecode(currCell, &command, &operand)){
return -1 ;
}
switch (command) {
case READ:
if (cu_read(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case WRITE:
if (cu_write(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case LOAD :
if (cu_load(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case STORE :
if (cu_store(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case JUMP :
if (cu_jump(operand))
return -1 ;
break ;
case JNEG :
if (cu_jneg(operand))
return -1 ;
break ;
case JZ :
if (cu_jz(operand))
return -1 ;
break ;
case HALT :
return -1 ;
break ;
default:
if (ALU(command, operand))
return -1 ;
break ;
}
return 0 ;
}
int cu_read(unsigned short int operand){
rk_myTermRestore() ;
printf("Enter value of cell[\033[38;5;%dm0x%02X\033[0m] in \033[38;5;%dmHEX\033[0m format > ", colors::SOFT_GREEN, operand, colors::PEACH) ;
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
rk_myTermRegime(false, 0, 0, false, false) ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+' or buffer[0] == '-')
i = 1 ;
else{
res |= (1 << 14) ;
(buffer[0] == '-') ? (res |= (1 << 13)) : i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
res |= (1 << 15) ;
}
else{
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if (number > 0x3FFF)
res |= (1 << 15) ;
else
{
number &= 0x3FFF ;
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value)){
res |= (1 << 15) ;
}
else
res |= value ;
}
}
else{
if (number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
res |= (1 << 15) ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
}
if (sc_memorySet(operand, (unsigned short int)res))
return -1 ;
return 0 ;
}
int cu_write(unsigned short int operand){
unsigned short int value;
if(sc_memoryGet(operand, &value)){
return -1 ;
}
printf("Value in a cell [\033[38;5;%dm0x%02X\033[0m] < ", colors::SOFT_GREEN, operand) ;
if ((value >> 14) & 1)
if ((value >> 13) & 1)
printf("-%04X", (
(value - 1)) & 0x3FFF) ;
else
printf(" %04X", value & 0x1FFF) ;
else
printf("+%04X", value) ;
getchar() ;
return 0 ;
}
int cu_load(unsigned short int operand){
unsigned short int value;
if (sc_memoryGet(operand, &value)){
return -1 ;
}
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return - 1;
}
sc_accumulator = value ;
return 0 ;
}
int cu_store(unsigned short int operand){
if (sc_memorySet(operand, sc_accumulator))
return -1 ;
return 0 ;
}
int cu_jump(unsigned short int operand){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
return 0 ;
}
int cu_jneg(unsigned short int operand){
if (((sc_accumulator >> 14) & 1) and ((sc_accumulator >> 13) & 1)){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
}
else
sc_instructionCounter++ ;
return 0 ;
}
int cu_jz(unsigned short int operand){
if (((sc_accumulator >> 14) & 1) and ((sc_accumulator & 0x3FFF) == 0)){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
}
else
sc_instructionCounter++ ;
return 0 ;
}
myALU.hpp
#ifndef MYALU_HPP
#define MYALU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
int ALU(unsigned short int command, unsigned short int operand) ;
#endif //MYALU_HPP
myALU.cpp
#include "myALU.hpp"
int alu_add(unsigned short int value) ;
int alu_divide(unsigned short int operand) ;
int alu_mul(unsigned short int operand) ;
int alu_rcr(unsigned short int operand) ;
int ALU(unsigned short int command, unsigned short int operand){
unsigned short int value ;
switch (command) {
case ADD:
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
if (alu_add(value))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case SUB:
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
if ((value >> 13) & 1) // Отрицательное
value =
((value & 0x3FFF) - 1) ;
else
value = (
(value & 0x3FFF)) + 1 ;
value &= 0x3FFF ;
value |= (1 << 14) ;
if (alu_add(value))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case DIVIDE:
if (alu_divide(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case MUL:
if (alu_mul(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case RCR:
if (alu_rcr(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
default:
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
return 0 ;
}
int alu_add(unsigned short int value){
unsigned short int accumulator, res;
accumulator = sc_accumulator & 0x3FFF ;
value &= 0x3FFF;
if (((accumulator >> 13) & 1) and ((value >> 13) & 1)){ // Если оба отрицательны
value =
(value - 1) & 0x3FFF ;
Приложение. Листинг
Makefile
d.PHONY: all clean run
COMPILER := g++
FLAGS := -fdiagnostics-color=always -Werror -MMD
SRC_SC := src/sc
BUILD_SC := build/sc
LIBS_SC := libs/sc
SRC_SA := src/sa
BUILD_SA := build/sa
SRC_SB := src/sb
BUILD_SB := build/sb
BIN := bin
SC := simpleComputer
SA := simpleAssembler
SB := simpleBasic
all: create $(BIN)/$(SC) $(BIN)/$(SA) $(BIN)/$(SB)
-include $((BUILD_SC)/*.d
-include $((BUILD_SA)/*.d
-include $((BUILD_SB)/*.d
sc: create $(BIN)/$(SC)
run_sc: sc
./$(BIN)/$(SC)
$(BIN)/$(SC): $(LIBS_SC)/libsimpleComputer.a $(LIBS_SC)/libmyTerm.a $(LIBS_SC)/libmyBigChars.a $(LIBS_SC)/libmyReadkey.a $(LIBS_SC)/libmyUI.a $(LIBS_SC)/libmyALU.a $(LIBS_SC)/libmyCU.a $(BUILD_SC)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SC) $(BUILD_SC)/main.o -L $(LIBS_SC) -lsimpleComputer -lmyUI -lmyTerm -lmyBigChars -lmyReadkey -lmyCU -lmyALU
$(BUILD_SC)/%.o: $(SRC_SC)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
$(LIBS_SC)/libsimpleComputer.a: $(BUILD_SC)/simpleComputer.o
ar cr $@ $^
$(LIBS_SC)/libmyTerm.a: $(BUILD_SC)/myTerm.o
ar cr $@ $^
$(LIBS_SC)/libmyBigChars.a: $(BUILD_SC)/myBigChars.o
ar cr $@ $^
$(LIBS_SC)/libmyReadkey.a: $(BUILD_SC)/myReadkey.o
ar cr $@ $^
$(LIBS_SC)/libmyUI.a: $(BUILD_SC)/myUI.o
ar cr $@ $^
$(LIBS_SC)/libmyALU.a: $(BUILD_SC)/myALU.o
ar cr $@ $^
$(LIBS_SC)/libmyCU.a: $(BUILD_SC)/myCU.o
ar cr $@ $^
sa: create $(BIN)/$(SA)
run_sa: create $(BIN)/$(SA)
./$(BIN)/$(SA)
$(BIN)/$(SA): $(BUILD_SA)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SA) $(BUILD_SA)/main.o
$(BUILD_SA)/%.o: $(SRC_SA)/%.cpps
$(COMPILER) $(FLAGS) -c $^ -o $@
sb: create $(BIN)/$(SB)
run_sb: create $(BIN)/$(SB)
./$(BIN)/$(SB)
$(BIN)/$(SB): $(BUILD_SB)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SB) $(BUILD_SB)/main.o
$(BUILD_SB)/%.o: $(SRC_SB)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
create:
mkdir -p $(BUILD_SC) $(BUILD_SA) $(BUILD_SB) $(LIBS_SC) $(BIN)
clean:
@rm -rf build libs $(BIN)
SimpleComputer
main.cpp
#include
#include "simpleComputer.hpp"
#include "myUI.hpp"
#include "myReadkey.hpp"
#include "myCU.hpp"
void signalHandler(int signal) ;
#include
int main(int argc, char const *argv[]){
ui_initial() ;
signal(SIGALRM, signalHandler) ;
signal(SIGUSR1, signalHandler) ;
bool zero, out, ignor, comm ;
keys key;
if (argc == 2){
sc_memoryLoad((char *)argv[1]) ;
}
else if (argc > 2){
ui_messageOutput((char *)"Exceeded the number of arguments", colors::RED) ;
return -1 ;
}
do {
sc_regGet(IGNORING_TACT_PULSES, &ignor);
ui_update() ;
rk_readKey(&key);
if (ignor){
sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
sc_regGet(OUT_OF_MEMORY, &out) ;
sc_regGet(INCORRECT_COMMAND, &comm) ;
if (zero || out || comm){
switch(key){
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
}
}
else{
switch(key){
case keys::KEY_UP:
ui_moveCurrMemPointer(keys::KEY_UP) ;
break ;
case keys::KEY_RIGHT:
ui_moveCurrMemPointer(keys::KEY_RIGHT) ;
break ;
case keys::KEY_DOWN:
ui_moveCurrMemPointer(keys::KEY_DOWN) ;
break ;
case keys::KEY_LEFT:
ui_moveCurrMemPointer(keys::KEY_LEFT) ;
break ;
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_R:
sc_regInit() ;
raise(SIGALRM) ;
break ;
case keys::KEY_T:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
CU() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
case keys::KEY_F5:
ui_setAccumulator() ;
break ;
case keys::KEY_F6:
ui_setICounter() ;
break ;
case keys::KEY_ENTER:
ui_setMCellValue() ;
break ;
}
}
}
else
if (key == keys::KEY_I)
raise(SIGUSR1) ;
} while(key != keys::KEY_ESC) ;
return 0 ;
}
void signalHandler(int signal){
switch (signal) {
case SIGALRM:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
if (CU()){
sc_regSet(IGNORING_TACT_PULSES, true);
ui_update() ;
alarm(0) ;
}
else
alarm(1) ;
rk_myTermRegime(false, 0, 0, false, false) ;
break ;
case SIGUSR1:
alarm(0) ;
ui_initial() ;
break ;
default:
break ;
}
}
simpleComputer.hpp
#ifndef SIMPLECOMPUTER_HPP
#define SIMPLECOMPUTER_HPP
#include
#define OVERFLOW 0 // Переполнение при выполнении операции
#define DIVISION_ERR_BY_ZERO 1 // Ошибка деления на 0
#define OUT_OF_MEMORY 2 // Ошибка выхода за границы памяти
#define IGNORING_TACT_PULSES 3 // Игнорирование тактовых импульсов
#define INCORRECT_COMMAND 4 // Указана неверная команда
const short int SC_REG_SIZE = 5 ;
const short int SC_MEM_SIZE = 100 ;
extern unsigned short int sc_accumulator ;
extern uint8_t sc_instructionCounter ;
int sc_memoryInit () ;
int sc_memorySet (unsigned short int address, unsigned short int value) ;
int sc_memoryGet (unsigned short int address, unsigned short int * value) ;
int sc_memorySave (char* filename) ;
int sc_memoryLoad (char* filename) ;
int sc_regInit () ;
int sc_regSet (int8_t reg, bool value) ;
int sc_regGet (int8_t reg, bool * value) ;
int sc_commandEncode (unsigned short int command, unsigned short int operand, unsigned short int * value) ;
int sc_commandDecode (unsigned short int value, unsigned short int * command, unsigned short int * operand) ;
#endif //SIMPLECOMPUTER_HPP
simpleComputer.cpp
#include "simpleComputer.hpp"
unsigned short int sc_memory[SC_MEM_SIZE] ;
uint8_t sc_regFLAGS ;
unsigned short int sc_accumulator ;
uint8_t sc_instructionCounter ;
/// Инициализирует оперативную память SC, задавая всем её ячейкам нулевые значения
/// \return 0
int sc_memoryInit()
{
sc_instructionCounter = 0 ;
for (unsigned short & mem : sc_memory)
mem = 0 ;
return 0 ;
}
/// Задает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySet(unsigned short int address, unsigned short int value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_memory[address] = value ;
return 0 ;
}
/// Возвращает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryGet(unsigned short int address, unsigned short int * value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
*value = sc_memory[address] ;
return 0 ;
}
/// Сохраняет содержимое памяти в файл в бинарном виде
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySave(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "wb"))){
return -1 ;
}
fwrite(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Загружает из указанного файла содержимое оперативной памяти
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryLoad(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "rb"))){
return -1 ;
}
fread(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Инициализирует регистр флагов нулевым значением
/// \return 0
int sc_regInit(){
sc_regFLAGS = 0 ;
return 0 ;
}
/// Устанавливает значение указанного регистра флагов
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regSet(int8_t reg, bool value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
value == 1 ? (sc_regFLAGS |= (1 << reg)) : (sc_regFLAGS &=
(1 << reg)) ;
return 0 ;
}
/// Возвращает значение указанного флага
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regGet(int8_t reg, bool *value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
*value = sc_regFLAGS & (1 << reg) ;
return 0 ;
}
/// Кодирует команду с указанным номером и операндом и помещает результат в value
/// \param command - команда
/// \param operand - операнд
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandEncode(unsigned short int command, unsigned short int operand, unsigned short int * value){
if (command > 0x7F)
return -1 ;
if (operand > 0x7F)
return -1 ;
* value = 0 ;
/* Операнд */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (operand >> i) & 1 ;
*value |= (bit << i) ;
}
/* Команда */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (command >> i) & 1 ;
*value |= (bit << (i + 7)) ;
}
return 0 ;
}
/// Декодирует значение как команду SС
/// \param value - значение
/// \param command - команда
/// \param operand - операнд
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandDecode(unsigned short int value, unsigned short int * command, unsigned short int * operand){
int tmpCom = 0, tmpOp = 0 ;
if ((value >> 14) & 1){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> i) & 1 ;
tmpOp |= (bit << i) ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> (i + 7)) & 1 ;
tmpCom |= (bit << i) ;
}
* command = tmpCom ;
* operand = tmpOp ;
return 0 ;
}
myTerm.hpp
#ifndef MYTERM_HPP
#define MYTERM_HPP
#include
#include
enum colors {
RED = 196,
PEACH = 203,
GREEN = 10,
SOFT_GREEN =192,
BLUE = 20,
BLACK = 16,
GRAY = 240,
WHITE = 15,
DEFAULT = 0};
int mt_clrScreen () ;
int mt_gotoXY(unsigned int col,unsigned int row) ;
int mt_getScreenSize(unsigned int *rows, unsigned int* cols) ;
int mt_setFGcolor(enum colors color) ;
int mt_setBGcolor(enum colors color) ;
int mt_setDefaultColorSettings() ;
#endif //MYTERM_HPP
myTerm.cpp
#include "myTerm.hpp"
/// Производит очистку и перемещение курсора в левый верхний угол экрана
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_clrScreen (){
printf("\033[H\033[2J") ;
return 0 ;
}
/// Перемещает курсор в указанную позицию
/// \param col - столбец
/// \param row - строка
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_gotoXY(unsigned int col, unsigned int row)
{
unsigned int rows, cols ;
if (mt_getScreenSize(&rows, &cols) == -1)
return -1 ;
if ((row > rows) || (row <= 0)||(col > cols) || (col <= 0))
return -1 ;
printf("\033[%d;%dH", row, col) ;
return 0 ;
}
/// Определяет размер экрана терминала
/// \param rows - кол-во строк
/// \param cols - кол-во столбцов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_getScreenSize(unsigned int *rows, unsigned int *cols){
winsize ws{} ;
if (ioctl(1, TIOCGWINSZ, &ws))
return -1 ;
* rows = ws.ws_row ;
* cols = ws.ws_col ;
return 0 ;
}
/// Устанавливает цвет последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setFGcolor(enum colors color){
printf("\033[38;5;%dm",color) ;
return 0 ;
}
/// Устанавливает цвет фона последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setBGcolor(enum colors color){
printf("\033[48;5;%dm",color) ;
return 0 ;
}
/// Возвращает цвета в стандартное состояние
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setDefaultColorSettings(){
printf("\033[0m") ;
return 0 ;
}
myUI.hpp
#ifndef MYUI_HPP
#define MYUI_HPP
#include
#include "myBigChars.hpp"
#include "myReadkey.hpp"
#include "simpleComputer.hpp"
int ui_initial() ;
int ui_update() ;
int setCurrMemPointer_to_ICounter() ;
int ui_moveCurrMemPointer(keys key) ;
int ui_setMCellValue() ;
int ui_saveMemory() ;
int ui_loadMemory() ;
int ui_setAccumulator() ;
int ui_setICounter() ;
bool checkCorrectInputHEX(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color);
int clearBuffIn() ;
#endif //MYUI_HPP
myUI.cpp
#include "myUI.hpp"
#include "myReadkey.hpp"
int8_t currMemCell = 0 ;
int drawingBoxes() ;
int drawingTexts() ;
int drawingMemory() ;
int drawingAccumulator() ;
int drawingInstructionCounter() ;
int drawingOperation() ;
int drawingFlags() ;
int drawingBigChar() ;
bool checkCorrectInputHEX(const char *buffer) ;
bool checkCorrectInputDEC(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color) ;
/// "Инициализация" интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_initial(){
currMemCell = 0 ;
if (rk_myTermSave())
return -1 ;
sc_memoryInit() ;
sc_accumulator &= (1 << 14) ;
sc_regInit() ;
sc_regSet(IGNORING_TACT_PULSES, true) ;
return 0 ;
}
/// Обновление интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_update(){
mt_clrScreen() ;
if (drawingBoxes())
return -1 ;
if (drawingTexts())
return -1 ;
if (drawingMemory())
return -1 ;
if (drawingAccumulator())
return -1 ;
if (drawingInstructionCounter())
return -1 ;
if (drawingOperation())
return -1 ;
if (drawingFlags())
return -1 ;
if (drawingBigChar())
return -1 ;
mt_gotoXY(1, 23) ;
printf("Input/Output:\n") ;
return 0 ;
}
/// Перемещение выделенной ячейки на значение ICounter
/// \return 0
int setCurrMemPointer_to_ICounter(){
currMemCell = sc_instructionCounter ;
return 0 ;
}
/// Перемещение выделенной ячейки
/// \param key - Клавиша
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_moveCurrMemPointer(keys key){
switch (key) {
case keys::KEY_UP: (currMemCell <= 9) ? (currMemCell = 90 + currMemCell) : (currMemCell -= 10) ; return 0 ;
case keys::KEY_RIGHT: (!((currMemCell + 1) % 10)) ? (currMemCell -= 9) : (currMemCell += 1) ; return 0 ;
case keys::KEY_DOWN: (currMemCell >= 90) ? (currMemCell = currMemCell - 90) : (currMemCell += 10) ; return 0 ;
case keys::KEY_LEFT: (!(currMemCell % 10)) ? (currMemCell += 9) : (currMemCell -= 1) ; return 0 ;
}
return -1 ;
}
int ui_setMCellValue(){
printf("Set the value of the cell under the number \033[38;5;%dm0x%02X\033[0m\n", colors::SOFT_GREEN, currMemCell) ;
printf("Enter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+')
i = 1 ;
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
if (sc_memorySet(currMemCell, res))
return -1 ;
return 0 ;
}
int ui_saveMemory(){
char filename[102] ;
printf("Saving file...\n") ;
printf("Enter the file name to save > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
printf("\033[38;5;%dmThe file name is too long. The length is trimmed to the first 100 characters.\033[0m\n", BLUE) ;
clearBuffIn(); // очистка потока ввода
}
else
filename[strlen(filename) - 1] = '\0' ;
if (sc_memorySave(filename)){
ui_messageOutput((char *)"Failed to save memory", colors::RED) ;
return -1 ;
}
else
ui_messageOutput((char *)"Successful save", colors::GREEN) ;
return 0 ;
}
int ui_loadMemory(){
char filename[102] ;
printf("Loading file...\n") ;
printf("Enter the file name to load > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
ui_messageOutput((char *)"The name of the file to open is too long (up to 100 characters are allowed)", colors::BLUE) ;
clearBuffIn(); // очистка потока ввода
return -1 ;
}
filename[strlen(filename) - 1] = '\0' ;
if (sc_memoryLoad(filename)){
ui_messageOutput((char *)"Failed to load memory", colors::RED) ;
return -1 ;
}
return 0 ;
}
int ui_setAccumulator(){
// может ли в accumulator храниться команда ? (теперь нет)
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"Accumulator\"\033[0m", colors::GREEN) ;
printf("\nEnter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+'){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if(number > 0x3FFF){
ui_messageOutput((char *)"The command value must not exceed 14 bits (0x3FFF)", colors::RED) ;
return -1 ;
}
else
{
number &= 0x3FFF ;
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
else{
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
}
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
sc_accumulator = res ;
return 0 ;
}
int ui_setICounter(){
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"InstructionCounter\"\033[0m between \033[38;5;%dm00\033[0m and \033[38;5;%dm99\033[0m inclusive\n", colors::GREEN, colors::SOFT_GREEN, colors::SOFT_GREEN) ;
printf("Enter value in \033[38;5;%dmDEC\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
if (!checkCorrectInputDEC(buffer)){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(buffer, &tmp, 10);
if(number > 99){
ui_messageOutput((char *)"The value must not exceed the amount of memory", colors::RED) ;
return -1 ;
}
sc_instructionCounter = (uint8_t)number ;
return 0 ;
}
/// Отрисовка "боксов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBoxes(){
if (bc_box(1, 1, 61, 12)) // Окно Memory
return -1 ;
if (bc_box(62, 1, 22, 3)) // Окно accumulator
return -1 ;
if (bc_box(62, 4, 22, 3)) // Окно instructionCounter
return -1 ;
if (bc_box(62, 7, 22, 3)) // Окно Operation
return -1 ;
if (bc_box(62, 10, 22, 3)) // Окно Flags
return -1 ;
if (bc_box(1, 13, 52, 10)) // Окно BigChars
return -1 ;
if (bc_box(53, 13, 31, 10)) // Окно Keys
return -1 ;
return 0 ;
}
/// Отрисовка заголовков и текста
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingTexts(){
/* Заголовки */
mt_gotoXY(30,1) ;
printf(" Memory ") ;
mt_gotoXY(66,1) ;
printf(" accumulator ") ;
mt_gotoXY(63,4) ;
printf(" instructionCounter ") ;
mt_gotoXY(67,7) ;
printf(" Operation ") ;
mt_gotoXY(69,10) ;
printf(" Flags ") ;
mt_gotoXY(54,13) ;
printf(" Keys: ") ;
/* HotKeys */
char* hotK[] = {(char *)"l - load",
(char *)"s - save",
(char *)"r - run",
(char *)"t - step",
(char *)"i - reset",
(char *)"F5 - accumulator",
(char *)"F6 - instructionCounter"};
for (int i = 0 ; i < sizeof(hotK) / sizeof(*hotK) ; ++i) {
mt_gotoXY(54,i + 14) ;
printf("%s", hotK[i]) ;
}
return 0 ;
}
/// Отрисовка памяти
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingMemory(){
for (int i = 0 ; i < 10 ; ++i)
for (int j = 0 ; j < 10 ; ++j) {
mt_gotoXY(2 + (5 * j + j), 2 + i) ;
unsigned short int tmp ;
sc_memoryGet(i * 10 + j, &tmp) ;
if ((i * 10 + j) == currMemCell)
mt_setBGcolor(colors::GREEN) ;
if((tmp >> 14) & 1)
if((tmp >> 13) & 1)
printf("-%04X", (
(tmp - 1)) & 0x3FFF) ;
else
printf(" %04X", tmp & 0x1FFF) ;
else
printf("+%04X", tmp) ;
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка accumulator
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingAccumulator(){
mt_gotoXY(70,2) ;
// bool over ;
// sc_regGet(OVERFLOW, &over) ;
// if (over){
// mt_setFGcolor(colors::PEACH) ;
// printf(" over") ;
// mt_setDefaultColorSettings() ;
// }
// else{
if((sc_accumulator >> 14) & 1)
if((sc_accumulator >> 13) & 1)
printf("-%04X", (
(sc_accumulator - 1)) & 0x3FFF) ;
else
printf(" %04X", sc_accumulator & 0x1FFF) ;
else
printf("+%04X", sc_accumulator) ;
// }
return 0 ;
}
/// Отрисовка Operation
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingOperation(){
mt_gotoXY(69,8) ;
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1)){
unsigned short int operand, command ;
sc_commandDecode(tmp, &command, &operand) ;
printf("+%02X:%02X", command, operand) ;
}
else{
unsigned short int left, right ;
bool negative = (tmp >> 13) & 1 ;
if(negative)
tmp = (
(tmp - 1)) & 0x3FFF ;
else
tmp &= 0x1FFF ;
left = tmp >> 8 ;
right = tmp & 0xFF ;
negative ? printf("-%02X:%02X", left, right) : printf(" %02X:%02X", left, right) ;
}
return 0 ;
}
/// Отрисовка instructionCounter
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingInstructionCounter(){
mt_gotoXY(71,5) ;
// bool over, zero, out, comm ;
// sc_regGet(OVERFLOW, &over) ;
// sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
// sc_regGet(OUT_OF_MEMORY, &out) ;
// sc_regGet(INCORRECT_COMMAND, &comm) ;
// mt_gotoXY(71,5) ;
// if (over || zero || out || comm){
// mt_setFGcolor(colors::SOFT_GREEN) ;
// printf("null") ;
// mt_setDefaultColorSettings() ;
// }
// else
printf("%04X", sc_instructionCounter) ;
return 0 ;
}
/// Отрисовка флагов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingFlags(){
char tmp[] = {'O', 'Z', 'M', 'I', 'C'};
for (int i = 0 ; i < SC_REG_SIZE ; ++i) {
bool value ;
if (sc_regGet(i, &value))
return -1 ;
mt_gotoXY(68 + (i * 2), 11) ;
if (value){
mt_setFGcolor(colors::PEACH) ;
printf("%c", tmp[i]) ;
}
else{
mt_setFGcolor(colors::GRAY) ;
printf("%c", tmp[i]) ;
}
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка "BigChar'ов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBigChar(){
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1))
bc_printBigChar(bc[16], 2, 14, GREEN) ;
else if((tmp >> 13) & 1){
bc_printBigChar(bc[17], 2, 14, GREEN) ;
tmp = (
(tmp - 1)) & 0x3FFF;
}
else
tmp &= 0x3FFF ;
for (int i = 0; i < 4; ++i) {
int ch = (tmp & ( 0xF << (4 * (3 - i)) )) >> (4 * (3 - i)) ;
bc_printBigChar(bc[ch], 2 + 8 * (i + 1) + 2 * (i + 1), 14, GREEN) ;
}
return 0 ;
}
bool checkCorrectInputHEX(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 4)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isxdigit(buffer[i])))
return false ;
return true ;
}
bool checkCorrectInputDEC(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 5)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isdigit(buffer[i])))
return false ;
return true ;
}
int ui_messageOutput(char *str, enum colors color){
printf("\033[38;5;%dm%s\033[0m", color, str) ;
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
return 0 ;
}
int clearBuffIn(){
int c;
do {
c = getchar();
} while (c != '\n' && c != '\0');
return 0 ;
}
myReadkey.hpp
#ifndef MYREADKEY_HPP
#define MYREADKEY_HPP
#include
#include
#include
extern termios save;
enum keys
{
KEY_L,
KEY_S,
KEY_R,
KEY_T,
KEY_I,
KEY_F5,
KEY_F6 ,
KEY_UP,
KEY_DOWN,
KEY_RIGHT,
KEY_LEFT,
KEY_ESC,
KEY_ENTER,
KEY_OTHER,
};
int rk_readKey(enum keys *key) ;
int rk_myTermSave() ;
int rk_myTermRestore() ;
int rk_myTermRegime (bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint) ;
#endif //MYREADKEY_HPP
myReadkey.cpp
#include "myReadkey.hpp"
termios save;
/// Возвращающую первую клавишу, которую нажал пользователь
/// \param key - Адрес переменной, в которую возвращается номер нажатой клавиши
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_readKey (enum keys * key){
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
rk_myTermRestore() ;
if (buffer[0] == '\033')
if (buffer[1] == '\0')
*key = KEY_ESC ;
else if (buffer[1] == '[')
if (buffer[2] == 'A' and buffer[3] == '\0')
*key = KEY_UP ;
else if (buffer[2] == 'B' and buffer[3] == '\0')
*key = KEY_DOWN ;
else if (buffer[2] == 'C' and buffer[3] == '\0')
*key = KEY_RIGHT ;
else if (buffer[2] == 'D' and buffer[3] == '\0')
*key = KEY_LEFT ;
else if (buffer[2] == '1' and buffer[3] == '5')
*key = KEY_F5 ;
else if (buffer[2] == '1' and buffer[3] == '7')
*key = KEY_F6 ;
else
*key = KEY_OTHER ;
else
*key = KEY_OTHER ;
else if (buffer[0] == '\n' and buffer[1] == '\0')
*key = KEY_ENTER ;
else
if ((buffer[0] == 'l' or buffer[0] == 'L') and buffer[1] == '\0')
*key = KEY_L ;
else if ((buffer[0] == 's' or buffer[0] == 'S') and buffer[1] == '\0')
*key = KEY_S ;
else if ((buffer[0] == 'r' or buffer[0] == 'R') and buffer[1] == '\0')
*key = KEY_R ;
else if ((buffer[0] == 't' or buffer[0] == 'T') and buffer[1] == '\0')
*key = KEY_T ;
else if ((buffer[0] == 'i' or buffer[0] == 'I') and buffer[1] == '\0')
*key = KEY_I ;
else
*key = KEY_OTHER ;
return 0 ;
}
/// Функция, сохраняющая текущие параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermSave(){
if (tcgetattr(fileno(stdin), &save))
return -1 ;
return 0 ;
}
/// Функция, восстанавливающая сохраненные параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRestore(){
tcsetattr(fileno(stdin), TCSAFLUSH, &save) ;
return 0 ;
}
/// Функция, переключающая режим работы терминала (канонический / неканонический)
/// \param regime
/// \param vtime
/// \param vmin
/// \param echo
/// \param sigint
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRegime(bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint){
termios curr{} ;
tcgetattr(fileno(stdin), &curr) ;
if(regime)
curr.c_lflag |= ICANON ;
else{
curr.c_lflag &=
ICANON ;
sigint ? (curr.c_lflag |= ISIG) : (curr.c_lflag &=
ISIG) ;
echo ? (curr.c_lflag |= ECHO) : (curr.c_lflag &=
ECHO) ;
curr.c_cc[VMIN] = vmin ;
curr.c_cc[VTIME] = vtime ;
}
tcsetattr(0,TCSAFLUSH,&curr) ;
return 0 ;
}
commands.hpp
#ifndef COMMANDS_HPP
#define COMMANDS_HPP
#define READ 0x10
#define WRITE 0x11
#define LOAD 0x20
#define STORE 0x21
#define ADD 0x30
#define SUB 0x31
#define DIVIDE 0x32
#define MUL 0x33
#define JUMP 0x40
#define JNEG 0x41
#define JZ 0x42
#define HALT 0x43
#define RCR 0x63
#endif //COMMANDS_HPP
myCU.hpp
#ifndef CU_HPP
#define CU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
#include "myALU.hpp"
int CU() ;
#endif //CU_HPP
myCU.cpp
#include "myCU.hpp"
int cu_read(unsigned short int operand) ;
int cu_write(unsigned short int operand) ;
int cu_load(unsigned short int operand) ;
int cu_store(unsigned short int operand) ;
int cu_jump(unsigned short int operand) ;
int cu_jneg(unsigned short int operand) ;
int cu_jz(unsigned short int operand) ;
int CU (){
unsigned short int command = 0;
unsigned short int operand = 0;
unsigned short int currCell;
sc_memoryGet(sc_instructionCounter, &currCell) ;
if (sc_commandDecode(currCell, &command, &operand)){
return -1 ;
}
switch (command) {
case READ:
if (cu_read(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case WRITE:
if (cu_write(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case LOAD :
if (cu_load(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case STORE :
if (cu_store(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case JUMP :
if (cu_jump(operand))
return -1 ;
break ;
case JNEG :
if (cu_jneg(operand))
return -1 ;
break ;
case JZ :
if (cu_jz(operand))
return -1 ;
break ;
case HALT :
return -1 ;
break ;
default:
if (ALU(command, operand))
return -1 ;
break ;
}
return 0 ;
}
int cu_read(unsigned short int operand){
rk_myTermRestore() ;
printf("Enter value of cell[\033[38;5;%dm0x%02X\033[0m] in \033[38;5;%dmHEX\033[0m format > ", colors::SOFT_GREEN, operand, colors::PEACH) ;
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
rk_myTermRegime(false, 0, 0, false, false) ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+' or buffer[0] == '-')
i = 1 ;
else{
res |= (1 << 14) ;
(buffer[0] == '-') ? (res |= (1 << 13)) : i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
res |= (1 << 15) ;
}
else{
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if (number > 0x3FFF)
res |= (1 << 15) ;
else
{
number &= 0x3FFF ;
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value)){
res |= (1 << 15) ;
}
else
res |= value ;
}
}
else{
if (number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
res |= (1 << 15) ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
}
if (sc_memorySet(operand, (unsigned short int)res))
return -1 ;
return 0 ;
}
int cu_write(unsigned short int operand){
unsigned short int value;
if(sc_memoryGet(operand, &value)){
return -1 ;
}
printf("Value in a cell [\033[38;5;%dm0x%02X\033[0m] < ", colors::SOFT_GREEN, operand) ;
if ((value >> 14) & 1)
if ((value >> 13) & 1)
printf("-%04X", (
(value - 1)) & 0x3FFF) ;
else
printf(" %04X", value & 0x1FFF) ;
else
printf("+%04X", value) ;
getchar() ;
return 0 ;
}
int cu_load(unsigned short int operand){
unsigned short int value;
if (sc_memoryGet(operand, &value)){
return -1 ;
}
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return - 1;
}
sc_accumulator = value ;
return 0 ;
}
int cu_store(unsigned short int operand){
if (sc_memorySet(operand, sc_accumulator))
return -1 ;
return 0 ;
}
int cu_jump(unsigned short int operand){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
return 0 ;
}
int cu_jneg(unsigned short int operand){
if (((sc_accumulator >> 14) & 1) and ((sc_accumulator >> 13) & 1)){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
}
else
sc_instructionCounter++ ;
return 0 ;
}
int cu_jz(unsigned short int operand){
if (((sc_accumulator >> 14) & 1) and ((sc_accumulator & 0x3FFF) == 0)){
if (operand > 0x63){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_instructionCounter = operand ;
}
else
sc_instructionCounter++ ;
return 0 ;
}
myALU.hpp
#ifndef MYALU_HPP
#define MYALU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
int ALU(unsigned short int command, unsigned short int operand) ;
#endif //MYALU_HPP
myALU.cpp
#include "myALU.hpp"
int alu_add(unsigned short int value) ;
int alu_divide(unsigned short int operand) ;
int alu_mul(unsigned short int operand) ;
int alu_rcr(unsigned short int operand) ;
int ALU(unsigned short int command, unsigned short int operand){
unsigned short int value ;
switch (command) {
case ADD:
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
if (alu_add(value))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case SUB:
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
if ((value >> 13) & 1) // Отрицательное
value =
((value & 0x3FFF) - 1) ;
Приложение. Листинг
Makefile
d.PHONY: all clean run
COMPILER := g++
FLAGS := -fdiagnostics-color=always -Werror -MMD
SRC_SC := src/sc
BUILD_SC := build/sc
LIBS_SC := libs/sc
SRC_SA := src/sa
BUILD_SA := build/sa
SRC_SB := src/sb
BUILD_SB := build/sb
BIN := bin
SC := simpleComputer
SA := simpleAssembler
SB := simpleBasic
all: create $(BIN)/$(SC) $(BIN)/$(SA) $(BIN)/$(SB)
-include $((BUILD_SC)/*.d
-include $((BUILD_SA)/*.d
-include $((BUILD_SB)/*.d
sc: create $(BIN)/$(SC)
run_sc: sc
./$(BIN)/$(SC)
$(BIN)/$(SC): $(LIBS_SC)/libsimpleComputer.a $(LIBS_SC)/libmyTerm.a $(LIBS_SC)/libmyBigChars.a $(LIBS_SC)/libmyReadkey.a $(LIBS_SC)/libmyUI.a $(LIBS_SC)/libmyALU.a $(LIBS_SC)/libmyCU.a $(BUILD_SC)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SC) $(BUILD_SC)/main.o -L $(LIBS_SC) -lsimpleComputer -lmyUI -lmyTerm -lmyBigChars -lmyReadkey -lmyCU -lmyALU
$(BUILD_SC)/%.o: $(SRC_SC)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
$(LIBS_SC)/libsimpleComputer.a: $(BUILD_SC)/simpleComputer.o
ar cr $@ $^
$(LIBS_SC)/libmyTerm.a: $(BUILD_SC)/myTerm.o
ar cr $@ $^
$(LIBS_SC)/libmyBigChars.a: $(BUILD_SC)/myBigChars.o
ar cr $@ $^
$(LIBS_SC)/libmyReadkey.a: $(BUILD_SC)/myReadkey.o
ar cr $@ $^
$(LIBS_SC)/libmyUI.a: $(BUILD_SC)/myUI.o
ar cr $@ $^
$(LIBS_SC)/libmyALU.a: $(BUILD_SC)/myALU.o
ar cr $@ $^
$(LIBS_SC)/libmyCU.a: $(BUILD_SC)/myCU.o
ar cr $@ $^
sa: create $(BIN)/$(SA)
run_sa: create $(BIN)/$(SA)
./$(BIN)/$(SA)
$(BIN)/$(SA): $(BUILD_SA)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SA) $(BUILD_SA)/main.o
$(BUILD_SA)/%.o: $(SRC_SA)/%.cpps
$(COMPILER) $(FLAGS) -c $^ -o $@
sb: create $(BIN)/$(SB)
run_sb: create $(BIN)/$(SB)
./$(BIN)/$(SB)
$(BIN)/$(SB): $(BUILD_SB)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SB) $(BUILD_SB)/main.o
$(BUILD_SB)/%.o: $(SRC_SB)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
create:
mkdir -p $(BUILD_SC) $(BUILD_SA) $(BUILD_SB) $(LIBS_SC) $(BIN)
clean:
@rm -rf build libs $(BIN)
SimpleComputer
main.cpp
#include
#include "simpleComputer.hpp"
#include "myUI.hpp"
#include "myReadkey.hpp"
#include "myCU.hpp"
void signalHandler(int signal) ;
#include
int main(int argc, char const *argv[]){
ui_initial() ;
signal(SIGALRM, signalHandler) ;
signal(SIGUSR1, signalHandler) ;
bool zero, out, ignor, comm ;
keys key;
if (argc == 2){
sc_memoryLoad((char *)argv[1]) ;
}
else if (argc > 2){
ui_messageOutput((char *)"Exceeded the number of arguments", colors::RED) ;
return -1 ;
}
do {
sc_regGet(IGNORING_TACT_PULSES, &ignor);
ui_update() ;
rk_readKey(&key);
if (ignor){
sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
sc_regGet(OUT_OF_MEMORY, &out) ;
sc_regGet(INCORRECT_COMMAND, &comm) ;
if (zero || out || comm){
switch(key){
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
}
}
else{
switch(key){
case keys::KEY_UP:
ui_moveCurrMemPointer(keys::KEY_UP) ;
break ;
case keys::KEY_RIGHT:
ui_moveCurrMemPointer(keys::KEY_RIGHT) ;
break ;
case keys::KEY_DOWN:
ui_moveCurrMemPointer(keys::KEY_DOWN) ;
break ;
case keys::KEY_LEFT:
ui_moveCurrMemPointer(keys::KEY_LEFT) ;
break ;
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_R:
sc_regInit() ;
raise(SIGALRM) ;
break ;
case keys::KEY_T:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
CU() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
case keys::KEY_F5:
ui_setAccumulator() ;
break ;
case keys::KEY_F6:
ui_setICounter() ;
break ;
case keys::KEY_ENTER:
ui_setMCellValue() ;
break ;
}
}
}
else
if (key == keys::KEY_I)
raise(SIGUSR1) ;
} while(key != keys::KEY_ESC) ;
return 0 ;
}
void signalHandler(int signal){
switch (signal) {
case SIGALRM:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
if (CU()){
sc_regSet(IGNORING_TACT_PULSES, true);
ui_update() ;
alarm(0) ;
}
else
alarm(1) ;
rk_myTermRegime(false, 0, 0, false, false) ;
break ;
case SIGUSR1:
alarm(0) ;
ui_initial() ;
break ;
default:
break ;
}
}
simpleComputer.hpp
#ifndef SIMPLECOMPUTER_HPP
#define SIMPLECOMPUTER_HPP
#include
#define OVERFLOW 0 // Переполнение при выполнении операции
#define DIVISION_ERR_BY_ZERO 1 // Ошибка деления на 0
#define OUT_OF_MEMORY 2 // Ошибка выхода за границы памяти
#define IGNORING_TACT_PULSES 3 // Игнорирование тактовых импульсов
#define INCORRECT_COMMAND 4 // Указана неверная команда
const short int SC_REG_SIZE = 5 ;
const short int SC_MEM_SIZE = 100 ;
extern unsigned short int sc_accumulator ;
extern uint8_t sc_instructionCounter ;
int sc_memoryInit () ;
int sc_memorySet (unsigned short int address, unsigned short int value) ;
int sc_memoryGet (unsigned short int address, unsigned short int * value) ;
int sc_memorySave (char* filename) ;
int sc_memoryLoad (char* filename) ;
int sc_regInit () ;
int sc_regSet (int8_t reg, bool value) ;
int sc_regGet (int8_t reg, bool * value) ;
int sc_commandEncode (unsigned short int command, unsigned short int operand, unsigned short int * value) ;
int sc_commandDecode (unsigned short int value, unsigned short int * command, unsigned short int * operand) ;
#endif //SIMPLECOMPUTER_HPP
simpleComputer.cpp
#include "simpleComputer.hpp"
unsigned short int sc_memory[SC_MEM_SIZE] ;
uint8_t sc_regFLAGS ;
unsigned short int sc_accumulator ;
uint8_t sc_instructionCounter ;
/// Инициализирует оперативную память SC, задавая всем её ячейкам нулевые значения
/// \return 0
int sc_memoryInit()
{
sc_instructionCounter = 0 ;
for (unsigned short & mem : sc_memory)
mem = 0 ;
return 0 ;
}
/// Задает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySet(unsigned short int address, unsigned short int value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_memory[address] = value ;
return 0 ;
}
/// Возвращает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryGet(unsigned short int address, unsigned short int * value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
*value = sc_memory[address] ;
return 0 ;
}
/// Сохраняет содержимое памяти в файл в бинарном виде
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySave(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "wb"))){
return -1 ;
}
fwrite(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Загружает из указанного файла содержимое оперативной памяти
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryLoad(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "rb"))){
return -1 ;
}
fread(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Инициализирует регистр флагов нулевым значением
/// \return 0
int sc_regInit(){
sc_regFLAGS = 0 ;
return 0 ;
}
/// Устанавливает значение указанного регистра флагов
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regSet(int8_t reg, bool value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
value == 1 ? (sc_regFLAGS |= (1 << reg)) : (sc_regFLAGS &=
(1 << reg)) ;
return 0 ;
}
/// Возвращает значение указанного флага
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regGet(int8_t reg, bool *value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
*value = sc_regFLAGS & (1 << reg) ;
return 0 ;
}
/// Кодирует команду с указанным номером и операндом и помещает результат в value
/// \param command - команда
/// \param operand - операнд
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandEncode(unsigned short int command, unsigned short int operand, unsigned short int * value){
if (command > 0x7F)
return -1 ;
if (operand > 0x7F)
return -1 ;
* value = 0 ;
/* Операнд */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (operand >> i) & 1 ;
*value |= (bit << i) ;
}
/* Команда */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (command >> i) & 1 ;
*value |= (bit << (i + 7)) ;
}
return 0 ;
}
/// Декодирует значение как команду SС
/// \param value - значение
/// \param command - команда
/// \param operand - операнд
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandDecode(unsigned short int value, unsigned short int * command, unsigned short int * operand){
int tmpCom = 0, tmpOp = 0 ;
if ((value >> 14) & 1){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> i) & 1 ;
tmpOp |= (bit << i) ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> (i + 7)) & 1 ;
tmpCom |= (bit << i) ;
}
* command = tmpCom ;
* operand = tmpOp ;
return 0 ;
}
myTerm.hpp
#ifndef MYTERM_HPP
#define MYTERM_HPP
#include
#include
enum colors {
RED = 196,
PEACH = 203,
GREEN = 10,
SOFT_GREEN =192,
BLUE = 20,
BLACK = 16,
GRAY = 240,
WHITE = 15,
DEFAULT = 0};
int mt_clrScreen () ;
int mt_gotoXY(unsigned int col,unsigned int row) ;
int mt_getScreenSize(unsigned int *rows, unsigned int* cols) ;
int mt_setFGcolor(enum colors color) ;
int mt_setBGcolor(enum colors color) ;
int mt_setDefaultColorSettings() ;
#endif //MYTERM_HPP
myTerm.cpp
#include "myTerm.hpp"
/// Производит очистку и перемещение курсора в левый верхний угол экрана
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_clrScreen (){
printf("\033[H\033[2J") ;
return 0 ;
}
/// Перемещает курсор в указанную позицию
/// \param col - столбец
/// \param row - строка
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_gotoXY(unsigned int col, unsigned int row)
{
unsigned int rows, cols ;
if (mt_getScreenSize(&rows, &cols) == -1)
return -1 ;
if ((row > rows) || (row <= 0)||(col > cols) || (col <= 0))
return -1 ;
printf("\033[%d;%dH", row, col) ;
return 0 ;
}
/// Определяет размер экрана терминала
/// \param rows - кол-во строк
/// \param cols - кол-во столбцов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_getScreenSize(unsigned int *rows, unsigned int *cols){
winsize ws{} ;
if (ioctl(1, TIOCGWINSZ, &ws))
return -1 ;
* rows = ws.ws_row ;
* cols = ws.ws_col ;
return 0 ;
}
/// Устанавливает цвет последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setFGcolor(enum colors color){
printf("\033[38;5;%dm",color) ;
return 0 ;
}
/// Устанавливает цвет фона последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setBGcolor(enum colors color){
printf("\033[48;5;%dm",color) ;
return 0 ;
}
/// Возвращает цвета в стандартное состояние
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setDefaultColorSettings(){
printf("\033[0m") ;
return 0 ;
}
myUI.hpp
#ifndef MYUI_HPP
#define MYUI_HPP
#include
#include "myBigChars.hpp"
#include "myReadkey.hpp"
#include "simpleComputer.hpp"
int ui_initial() ;
int ui_update() ;
int setCurrMemPointer_to_ICounter() ;
int ui_moveCurrMemPointer(keys key) ;
int ui_setMCellValue() ;
int ui_saveMemory() ;
int ui_loadMemory() ;
int ui_setAccumulator() ;
int ui_setICounter() ;
bool checkCorrectInputHEX(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color);
int clearBuffIn() ;
#endif //MYUI_HPP
myUI.cpp
#include "myUI.hpp"
#include "myReadkey.hpp"
int8_t currMemCell = 0 ;
int drawingBoxes() ;
int drawingTexts() ;
int drawingMemory() ;
int drawingAccumulator() ;
int drawingInstructionCounter() ;
int drawingOperation() ;
int drawingFlags() ;
int drawingBigChar() ;
bool checkCorrectInputHEX(const char *buffer) ;
bool checkCorrectInputDEC(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color) ;
/// "Инициализация" интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_initial(){
currMemCell = 0 ;
if (rk_myTermSave())
return -1 ;
sc_memoryInit() ;
sc_accumulator &= (1 << 14) ;
sc_regInit() ;
sc_regSet(IGNORING_TACT_PULSES, true) ;
return 0 ;
}
/// Обновление интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_update(){
mt_clrScreen() ;
if (drawingBoxes())
return -1 ;
if (drawingTexts())
return -1 ;
if (drawingMemory())
return -1 ;
if (drawingAccumulator())
return -1 ;
if (drawingInstructionCounter())
return -1 ;
if (drawingOperation())
return -1 ;
if (drawingFlags())
return -1 ;
if (drawingBigChar())
return -1 ;
mt_gotoXY(1, 23) ;
printf("Input/Output:\n") ;
return 0 ;
}
/// Перемещение выделенной ячейки на значение ICounter
/// \return 0
int setCurrMemPointer_to_ICounter(){
currMemCell = sc_instructionCounter ;
return 0 ;
}
/// Перемещение выделенной ячейки
/// \param key - Клавиша
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_moveCurrMemPointer(keys key){
switch (key) {
case keys::KEY_UP: (currMemCell <= 9) ? (currMemCell = 90 + currMemCell) : (currMemCell -= 10) ; return 0 ;
case keys::KEY_RIGHT: (!((currMemCell + 1) % 10)) ? (currMemCell -= 9) : (currMemCell += 1) ; return 0 ;
case keys::KEY_DOWN: (currMemCell >= 90) ? (currMemCell = currMemCell - 90) : (currMemCell += 10) ; return 0 ;
case keys::KEY_LEFT: (!(currMemCell % 10)) ? (currMemCell += 9) : (currMemCell -= 1) ; return 0 ;
}
return -1 ;
}
int ui_setMCellValue(){
printf("Set the value of the cell under the number \033[38;5;%dm0x%02X\033[0m\n", colors::SOFT_GREEN, currMemCell) ;
printf("Enter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+')
i = 1 ;
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
if (sc_memorySet(currMemCell, res))
return -1 ;
return 0 ;
}
int ui_saveMemory(){
char filename[102] ;
printf("Saving file...\n") ;
printf("Enter the file name to save > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
printf("\033[38;5;%dmThe file name is too long. The length is trimmed to the first 100 characters.\033[0m\n", BLUE) ;
clearBuffIn(); // очистка потока ввода
}
else
filename[strlen(filename) - 1] = '\0' ;
if (sc_memorySave(filename)){
ui_messageOutput((char *)"Failed to save memory", colors::RED) ;
return -1 ;
}
else
ui_messageOutput((char *)"Successful save", colors::GREEN) ;
return 0 ;
}
int ui_loadMemory(){
char filename[102] ;
printf("Loading file...\n") ;
printf("Enter the file name to load > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
ui_messageOutput((char *)"The name of the file to open is too long (up to 100 characters are allowed)", colors::BLUE) ;
clearBuffIn(); // очистка потока ввода
return -1 ;
}
filename[strlen(filename) - 1] = '\0' ;
if (sc_memoryLoad(filename)){
ui_messageOutput((char *)"Failed to load memory", colors::RED) ;
return -1 ;
}
return 0 ;
}
int ui_setAccumulator(){
// может ли в accumulator храниться команда ? (теперь нет)
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"Accumulator\"\033[0m", colors::GREEN) ;
printf("\nEnter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+'){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if(number > 0x3FFF){
ui_messageOutput((char *)"The command value must not exceed 14 bits (0x3FFF)", colors::RED) ;
return -1 ;
}
else
{
number &= 0x3FFF ;
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
else{
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
}
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
sc_accumulator = res ;
return 0 ;
}
int ui_setICounter(){
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"InstructionCounter\"\033[0m between \033[38;5;%dm00\033[0m and \033[38;5;%dm99\033[0m inclusive\n", colors::GREEN, colors::SOFT_GREEN, colors::SOFT_GREEN) ;
printf("Enter value in \033[38;5;%dmDEC\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
if (!checkCorrectInputDEC(buffer)){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(buffer, &tmp, 10);
if(number > 99){
ui_messageOutput((char *)"The value must not exceed the amount of memory", colors::RED) ;
return -1 ;
}
sc_instructionCounter = (uint8_t)number ;
return 0 ;
}
/// Отрисовка "боксов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBoxes(){
if (bc_box(1, 1, 61, 12)) // Окно Memory
return -1 ;
if (bc_box(62, 1, 22, 3)) // Окно accumulator
return -1 ;
if (bc_box(62, 4, 22, 3)) // Окно instructionCounter
return -1 ;
if (bc_box(62, 7, 22, 3)) // Окно Operation
return -1 ;
if (bc_box(62, 10, 22, 3)) // Окно Flags
return -1 ;
if (bc_box(1, 13, 52, 10)) // Окно BigChars
return -1 ;
if (bc_box(53, 13, 31, 10)) // Окно Keys
return -1 ;
return 0 ;
}
/// Отрисовка заголовков и текста
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingTexts(){
/* Заголовки */
mt_gotoXY(30,1) ;
printf(" Memory ") ;
mt_gotoXY(66,1) ;
printf(" accumulator ") ;
mt_gotoXY(63,4) ;
printf(" instructionCounter ") ;
mt_gotoXY(67,7) ;
printf(" Operation ") ;
mt_gotoXY(69,10) ;
printf(" Flags ") ;
mt_gotoXY(54,13) ;
printf(" Keys: ") ;
/* HotKeys */
char* hotK[] = {(char *)"l - load",
(char *)"s - save",
(char *)"r - run",
(char *)"t - step",
(char *)"i - reset",
(char *)"F5 - accumulator",
(char *)"F6 - instructionCounter"};
for (int i = 0 ; i < sizeof(hotK) / sizeof(*hotK) ; ++i) {
mt_gotoXY(54,i + 14) ;
printf("%s", hotK[i]) ;
}
return 0 ;
}
/// Отрисовка памяти
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingMemory(){
for (int i = 0 ; i < 10 ; ++i)
for (int j = 0 ; j < 10 ; ++j) {
mt_gotoXY(2 + (5 * j + j), 2 + i) ;
unsigned short int tmp ;
sc_memoryGet(i * 10 + j, &tmp) ;
if ((i * 10 + j) == currMemCell)
mt_setBGcolor(colors::GREEN) ;
if((tmp >> 14) & 1)
if((tmp >> 13) & 1)
printf("-%04X", (
(tmp - 1)) & 0x3FFF) ;
else
printf(" %04X", tmp & 0x1FFF) ;
else
printf("+%04X", tmp) ;
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка accumulator
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingAccumulator(){
mt_gotoXY(70,2) ;
// bool over ;
// sc_regGet(OVERFLOW, &over) ;
// if (over){
// mt_setFGcolor(colors::PEACH) ;
// printf(" over") ;
// mt_setDefaultColorSettings() ;
// }
// else{
if((sc_accumulator >> 14) & 1)
if((sc_accumulator >> 13) & 1)
printf("-%04X", (
(sc_accumulator - 1)) & 0x3FFF) ;
else
printf(" %04X", sc_accumulator & 0x1FFF) ;
else
printf("+%04X", sc_accumulator) ;
// }
return 0 ;
}
/// Отрисовка Operation
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingOperation(){
mt_gotoXY(69,8) ;
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1)){
unsigned short int operand, command ;
sc_commandDecode(tmp, &command, &operand) ;
printf("+%02X:%02X", command, operand) ;
}
else{
unsigned short int left, right ;
bool negative = (tmp >> 13) & 1 ;
if(negative)
tmp = (
(tmp - 1)) & 0x3FFF ;
else
tmp &= 0x1FFF ;
left = tmp >> 8 ;
right = tmp & 0xFF ;
negative ? printf("-%02X:%02X", left, right) : printf(" %02X:%02X", left, right) ;
}
return 0 ;
}
/// Отрисовка instructionCounter
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingInstructionCounter(){
mt_gotoXY(71,5) ;
// bool over, zero, out, comm ;
// sc_regGet(OVERFLOW, &over) ;
// sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
// sc_regGet(OUT_OF_MEMORY, &out) ;
// sc_regGet(INCORRECT_COMMAND, &comm) ;
// mt_gotoXY(71,5) ;
// if (over || zero || out || comm){
// mt_setFGcolor(colors::SOFT_GREEN) ;
// printf("null") ;
// mt_setDefaultColorSettings() ;
// }
// else
printf("%04X", sc_instructionCounter) ;
return 0 ;
}
/// Отрисовка флагов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingFlags(){
char tmp[] = {'O', 'Z', 'M', 'I', 'C'};
for (int i = 0 ; i < SC_REG_SIZE ; ++i) {
bool value ;
if (sc_regGet(i, &value))
return -1 ;
mt_gotoXY(68 + (i * 2), 11) ;
if (value){
mt_setFGcolor(colors::PEACH) ;
printf("%c", tmp[i]) ;
}
else{
mt_setFGcolor(colors::GRAY) ;
printf("%c", tmp[i]) ;
}
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка "BigChar'ов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBigChar(){
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1))
bc_printBigChar(bc[16], 2, 14, GREEN) ;
else if((tmp >> 13) & 1){
bc_printBigChar(bc[17], 2, 14, GREEN) ;
tmp = (
(tmp - 1)) & 0x3FFF;
}
else
tmp &= 0x3FFF ;
for (int i = 0; i < 4; ++i) {
int ch = (tmp & ( 0xF << (4 * (3 - i)) )) >> (4 * (3 - i)) ;
bc_printBigChar(bc[ch], 2 + 8 * (i + 1) + 2 * (i + 1), 14, GREEN) ;
}
return 0 ;
}
bool checkCorrectInputHEX(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 4)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isxdigit(buffer[i])))
return false ;
return true ;
}
bool checkCorrectInputDEC(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 5)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isdigit(buffer[i])))
return false ;
return true ;
}
int ui_messageOutput(char *str, enum colors color){
printf("\033[38;5;%dm%s\033[0m", color, str) ;
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
return 0 ;
}
int clearBuffIn(){
int c;
do {
c = getchar();
} while (c != '\n' && c != '\0');
return 0 ;
}
myReadkey.hpp
#ifndef MYREADKEY_HPP
#define MYREADKEY_HPP
#include
#include
#include
extern termios save;
enum keys
{
KEY_L,
KEY_S,
KEY_R,
KEY_T,
KEY_I,
KEY_F5,
KEY_F6 ,
KEY_UP,
KEY_DOWN,
KEY_RIGHT,
KEY_LEFT,
KEY_ESC,
KEY_ENTER,
KEY_OTHER,
};
int rk_readKey(enum keys *key) ;
int rk_myTermSave() ;
int rk_myTermRestore() ;
int rk_myTermRegime (bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint) ;
#endif //MYREADKEY_HPP
myReadkey.cpp
#include "myReadkey.hpp"
termios save;
/// Возвращающую первую клавишу, которую нажал пользователь
/// \param key - Адрес переменной, в которую возвращается номер нажатой клавиши
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_readKey (enum keys * key){
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
rk_myTermRestore() ;
if (buffer[0] == '\033')
if (buffer[1] == '\0')
*key = KEY_ESC ;
else if (buffer[1] == '[')
if (buffer[2] == 'A' and buffer[3] == '\0')
*key = KEY_UP ;
else if (buffer[2] == 'B' and buffer[3] == '\0')
*key = KEY_DOWN ;
else if (buffer[2] == 'C' and buffer[3] == '\0')
*key = KEY_RIGHT ;
else if (buffer[2] == 'D' and buffer[3] == '\0')
*key = KEY_LEFT ;
else if (buffer[2] == '1' and buffer[3] == '5')
*key = KEY_F5 ;
else if (buffer[2] == '1' and buffer[3] == '7')
*key = KEY_F6 ;
else
*key = KEY_OTHER ;
else
*key = KEY_OTHER ;
else if (buffer[0] == '\n' and buffer[1] == '\0')
*key = KEY_ENTER ;
else
if ((buffer[0] == 'l' or buffer[0] == 'L') and buffer[1] == '\0')
*key = KEY_L ;
else if ((buffer[0] == 's' or buffer[0] == 'S') and buffer[1] == '\0')
*key = KEY_S ;
else if ((buffer[0] == 'r' or buffer[0] == 'R') and buffer[1] == '\0')
*key = KEY_R ;
else if ((buffer[0] == 't' or buffer[0] == 'T') and buffer[1] == '\0')
*key = KEY_T ;
else if ((buffer[0] == 'i' or buffer[0] == 'I') and buffer[1] == '\0')
*key = KEY_I ;
else
*key = KEY_OTHER ;
return 0 ;
}
/// Функция, сохраняющая текущие параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermSave(){
if (tcgetattr(fileno(stdin), &save))
return -1 ;
return 0 ;
}
/// Функция, восстанавливающая сохраненные параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRestore(){
tcsetattr(fileno(stdin), TCSAFLUSH, &save) ;
return 0 ;
}
/// Функция, переключающая режим работы терминала (канонический / неканонический)
/// \param regime
/// \param vtime
/// \param vmin
/// \param echo
/// \param sigint
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRegime(bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint){
termios curr{} ;
tcgetattr(fileno(stdin), &curr) ;
if(regime)
curr.c_lflag |= ICANON ;
else{
curr.c_lflag &=
ICANON ;
sigint ? (curr.c_lflag |= ISIG) : (curr.c_lflag &=
ISIG) ;
echo ? (curr.c_lflag |= ECHO) : (curr.c_lflag &=
ECHO) ;
curr.c_cc[VMIN] = vmin ;
curr.c_cc[VTIME] = vtime ;
}
tcsetattr(0,TCSAFLUSH,&curr) ;
return 0 ;
}
commands.hpp
#ifndef COMMANDS_HPP
#define COMMANDS_HPP
#define READ 0x10
#define WRITE 0x11
#define LOAD 0x20
#define STORE 0x21
#define ADD 0x30
#define SUB 0x31
#define DIVIDE 0x32
#define MUL 0x33
#define JUMP 0x40
#define JNEG 0x41
#define JZ 0x42
#define HALT 0x43
#define RCR 0x63
#endif //COMMANDS_HPP
myCU.hpp
#ifndef CU_HPP
#define CU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
#include "myALU.hpp"
int CU() ;
#endif //CU_HPP
myCU.cpp
#include "myCU.hpp"
int cu_read(unsigned short int operand) ;
int cu_write(unsigned short int operand) ;
int cu_load(unsigned short int operand) ;
int cu_store(unsigned short int operand) ;
int cu_jump(unsigned short int operand) ;
int cu_jneg(unsigned short int operand) ;
int cu_jz(unsigned short int operand) ;
int CU (){
unsigned short int command = 0;
unsigned short int operand = 0;
unsigned short int currCell;
sc_memoryGet(sc_instructionCounter, &currCell) ;
if (sc_commandDecode(currCell, &command, &operand)){
return -1 ;
}
switch (command) {
case READ:
if (cu_read(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case WRITE:
if (cu_write(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case LOAD :
if (cu_load(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case STORE :
if (cu_store(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case JUMP :
if (cu_jump(operand))
return -1 ;
break ;
case JNEG :
if (cu_jneg(operand))
return -1 ;
break ;
case JZ :
if (cu_jz(operand))
return -1 ;
break ;
case HALT :
return -1 ;
break ;
default:
if (ALU(command, operand))
return -1 ;
break ;
}
return 0 ;
}
int cu_read(unsigned short int operand){
rk_myTermRestore() ;
printf("Enter value of cell[\033[38;5;%dm0x%02X\033[0m] in \033[38;5;%dmHEX\033[0m format > ", colors::SOFT_GREEN, operand, colors::PEACH) ;
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
rk_myTermRegime(false, 0, 0, false, false) ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+' or buffer[0] == '-')
i = 1 ;
else{
res |= (1 << 14) ;
(buffer[0] == '-') ? (res |= (1 << 13)) : i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
res |= (1 << 15) ;
}
else{
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if (number > 0x3FFF)
res |= (1 << 15) ;
else
{
number &= 0x3FFF ;
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value)){
res |= (1 << 15) ;
}
else
res |= value ;
}
}
else{
if (number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
res |= (1 << 15) ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
Приложение. Листинг
Makefile
d.PHONY: all clean run
COMPILER := g++
FLAGS := -fdiagnostics-color=always -Werror -MMD
SRC_SC := src/sc
BUILD_SC := build/sc
LIBS_SC := libs/sc
SRC_SA := src/sa
BUILD_SA := build/sa
SRC_SB := src/sb
BUILD_SB := build/sb
BIN := bin
SC := simpleComputer
SA := simpleAssembler
SB := simpleBasic
all: create $(BIN)/$(SC) $(BIN)/$(SA) $(BIN)/$(SB)
-include $((BUILD_SC)/*.d
-include $((BUILD_SA)/*.d
-include $((BUILD_SB)/*.d
sc: create $(BIN)/$(SC)
run_sc: sc
./$(BIN)/$(SC)
$(BIN)/$(SC): $(LIBS_SC)/libsimpleComputer.a $(LIBS_SC)/libmyTerm.a $(LIBS_SC)/libmyBigChars.a $(LIBS_SC)/libmyReadkey.a $(LIBS_SC)/libmyUI.a $(LIBS_SC)/libmyALU.a $(LIBS_SC)/libmyCU.a $(BUILD_SC)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SC) $(BUILD_SC)/main.o -L $(LIBS_SC) -lsimpleComputer -lmyUI -lmyTerm -lmyBigChars -lmyReadkey -lmyCU -lmyALU
$(BUILD_SC)/%.o: $(SRC_SC)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
$(LIBS_SC)/libsimpleComputer.a: $(BUILD_SC)/simpleComputer.o
ar cr $@ $^
$(LIBS_SC)/libmyTerm.a: $(BUILD_SC)/myTerm.o
ar cr $@ $^
$(LIBS_SC)/libmyBigChars.a: $(BUILD_SC)/myBigChars.o
ar cr $@ $^
$(LIBS_SC)/libmyReadkey.a: $(BUILD_SC)/myReadkey.o
ar cr $@ $^
$(LIBS_SC)/libmyUI.a: $(BUILD_SC)/myUI.o
ar cr $@ $^
$(LIBS_SC)/libmyALU.a: $(BUILD_SC)/myALU.o
ar cr $@ $^
$(LIBS_SC)/libmyCU.a: $(BUILD_SC)/myCU.o
ar cr $@ $^
sa: create $(BIN)/$(SA)
run_sa: create $(BIN)/$(SA)
./$(BIN)/$(SA)
$(BIN)/$(SA): $(BUILD_SA)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SA) $(BUILD_SA)/main.o
$(BUILD_SA)/%.o: $(SRC_SA)/%.cpps
$(COMPILER) $(FLAGS) -c $^ -o $@
sb: create $(BIN)/$(SB)
run_sb: create $(BIN)/$(SB)
./$(BIN)/$(SB)
$(BIN)/$(SB): $(BUILD_SB)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SB) $(BUILD_SB)/main.o
$(BUILD_SB)/%.o: $(SRC_SB)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
create:
mkdir -p $(BUILD_SC) $(BUILD_SA) $(BUILD_SB) $(LIBS_SC) $(BIN)
clean:
@rm -rf build libs $(BIN)
SimpleComputer
main.cpp
#include
#include "simpleComputer.hpp"
#include "myUI.hpp"
#include "myReadkey.hpp"
#include "myCU.hpp"
void signalHandler(int signal) ;
#include
int main(int argc, char const *argv[]){
ui_initial() ;
signal(SIGALRM, signalHandler) ;
signal(SIGUSR1, signalHandler) ;
bool zero, out, ignor, comm ;
keys key;
if (argc == 2){
sc_memoryLoad((char *)argv[1]) ;
}
else if (argc > 2){
ui_messageOutput((char *)"Exceeded the number of arguments", colors::RED) ;
return -1 ;
}
do {
sc_regGet(IGNORING_TACT_PULSES, &ignor);
ui_update() ;
rk_readKey(&key);
if (ignor){
sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
sc_regGet(OUT_OF_MEMORY, &out) ;
sc_regGet(INCORRECT_COMMAND, &comm) ;
if (zero || out || comm){
switch(key){
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
}
}
else{
switch(key){
case keys::KEY_UP:
ui_moveCurrMemPointer(keys::KEY_UP) ;
break ;
case keys::KEY_RIGHT:
ui_moveCurrMemPointer(keys::KEY_RIGHT) ;
break ;
case keys::KEY_DOWN:
ui_moveCurrMemPointer(keys::KEY_DOWN) ;
break ;
case keys::KEY_LEFT:
ui_moveCurrMemPointer(keys::KEY_LEFT) ;
break ;
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_R:
sc_regInit() ;
raise(SIGALRM) ;
break ;
case keys::KEY_T:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
CU() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
case keys::KEY_F5:
ui_setAccumulator() ;
break ;
case keys::KEY_F6:
ui_setICounter() ;
break ;
case keys::KEY_ENTER:
ui_setMCellValue() ;
break ;
}
}
}
else
if (key == keys::KEY_I)
raise(SIGUSR1) ;
} while(key != keys::KEY_ESC) ;
return 0 ;
}
void signalHandler(int signal){
switch (signal) {
case SIGALRM:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
if (CU()){
sc_regSet(IGNORING_TACT_PULSES, true);
ui_update() ;
alarm(0) ;
}
else
alarm(1) ;
rk_myTermRegime(false, 0, 0, false, false) ;
break ;
case SIGUSR1:
alarm(0) ;
ui_initial() ;
break ;
default:
break ;
}
}
simpleComputer.hpp
#ifndef SIMPLECOMPUTER_HPP
#define SIMPLECOMPUTER_HPP
#include
#define OVERFLOW 0 // Переполнение при выполнении операции
#define DIVISION_ERR_BY_ZERO 1 // Ошибка деления на 0
#define OUT_OF_MEMORY 2 // Ошибка выхода за границы памяти
#define IGNORING_TACT_PULSES 3 // Игнорирование тактовых импульсов
#define INCORRECT_COMMAND 4 // Указана неверная команда
const short int SC_REG_SIZE = 5 ;
const short int SC_MEM_SIZE = 100 ;
extern unsigned short int sc_accumulator ;
extern uint8_t sc_instructionCounter ;
int sc_memoryInit () ;
int sc_memorySet (unsigned short int address, unsigned short int value) ;
int sc_memoryGet (unsigned short int address, unsigned short int * value) ;
int sc_memorySave (char* filename) ;
int sc_memoryLoad (char* filename) ;
int sc_regInit () ;
int sc_regSet (int8_t reg, bool value) ;
int sc_regGet (int8_t reg, bool * value) ;
int sc_commandEncode (unsigned short int command, unsigned short int operand, unsigned short int * value) ;
int sc_commandDecode (unsigned short int value, unsigned short int * command, unsigned short int * operand) ;
#endif //SIMPLECOMPUTER_HPP
simpleComputer.cpp
#include "simpleComputer.hpp"
unsigned short int sc_memory[SC_MEM_SIZE] ;
uint8_t sc_regFLAGS ;
unsigned short int sc_accumulator ;
uint8_t sc_instructionCounter ;
/// Инициализирует оперативную память SC, задавая всем её ячейкам нулевые значения
/// \return 0
int sc_memoryInit()
{
sc_instructionCounter = 0 ;
for (unsigned short & mem : sc_memory)
mem = 0 ;
return 0 ;
}
/// Задает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySet(unsigned short int address, unsigned short int value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_memory[address] = value ;
return 0 ;
}
/// Возвращает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryGet(unsigned short int address, unsigned short int * value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
*value = sc_memory[address] ;
return 0 ;
}
/// Сохраняет содержимое памяти в файл в бинарном виде
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySave(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "wb"))){
return -1 ;
}
fwrite(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Загружает из указанного файла содержимое оперативной памяти
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryLoad(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "rb"))){
return -1 ;
}
fread(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Инициализирует регистр флагов нулевым значением
/// \return 0
int sc_regInit(){
sc_regFLAGS = 0 ;
return 0 ;
}
/// Устанавливает значение указанного регистра флагов
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regSet(int8_t reg, bool value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
value == 1 ? (sc_regFLAGS |= (1 << reg)) : (sc_regFLAGS &=
(1 << reg)) ;
return 0 ;
}
/// Возвращает значение указанного флага
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regGet(int8_t reg, bool *value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
*value = sc_regFLAGS & (1 << reg) ;
return 0 ;
}
/// Кодирует команду с указанным номером и операндом и помещает результат в value
/// \param command - команда
/// \param operand - операнд
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandEncode(unsigned short int command, unsigned short int operand, unsigned short int * value){
if (command > 0x7F)
return -1 ;
if (operand > 0x7F)
return -1 ;
* value = 0 ;
/* Операнд */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (operand >> i) & 1 ;
*value |= (bit << i) ;
}
/* Команда */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (command >> i) & 1 ;
*value |= (bit << (i + 7)) ;
}
return 0 ;
}
/// Декодирует значение как команду SС
/// \param value - значение
/// \param command - команда
/// \param operand - операнд
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandDecode(unsigned short int value, unsigned short int * command, unsigned short int * operand){
int tmpCom = 0, tmpOp = 0 ;
if ((value >> 14) & 1){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> i) & 1 ;
tmpOp |= (bit << i) ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> (i + 7)) & 1 ;
tmpCom |= (bit << i) ;
}
* command = tmpCom ;
* operand = tmpOp ;
return 0 ;
}
myTerm.hpp
#ifndef MYTERM_HPP
#define MYTERM_HPP
#include
#include
enum colors {
RED = 196,
PEACH = 203,
GREEN = 10,
SOFT_GREEN =192,
BLUE = 20,
BLACK = 16,
GRAY = 240,
WHITE = 15,
DEFAULT = 0};
int mt_clrScreen () ;
int mt_gotoXY(unsigned int col,unsigned int row) ;
int mt_getScreenSize(unsigned int *rows, unsigned int* cols) ;
int mt_setFGcolor(enum colors color) ;
int mt_setBGcolor(enum colors color) ;
int mt_setDefaultColorSettings() ;
#endif //MYTERM_HPP
myTerm.cpp
#include "myTerm.hpp"
/// Производит очистку и перемещение курсора в левый верхний угол экрана
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_clrScreen (){
printf("\033[H\033[2J") ;
return 0 ;
}
/// Перемещает курсор в указанную позицию
/// \param col - столбец
/// \param row - строка
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_gotoXY(unsigned int col, unsigned int row)
{
unsigned int rows, cols ;
if (mt_getScreenSize(&rows, &cols) == -1)
return -1 ;
if ((row > rows) || (row <= 0)||(col > cols) || (col <= 0))
return -1 ;
printf("\033[%d;%dH", row, col) ;
return 0 ;
}
/// Определяет размер экрана терминала
/// \param rows - кол-во строк
/// \param cols - кол-во столбцов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_getScreenSize(unsigned int *rows, unsigned int *cols){
winsize ws{} ;
if (ioctl(1, TIOCGWINSZ, &ws))
return -1 ;
* rows = ws.ws_row ;
* cols = ws.ws_col ;
return 0 ;
}
/// Устанавливает цвет последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setFGcolor(enum colors color){
printf("\033[38;5;%dm",color) ;
return 0 ;
}
/// Устанавливает цвет фона последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setBGcolor(enum colors color){
printf("\033[48;5;%dm",color) ;
return 0 ;
}
/// Возвращает цвета в стандартное состояние
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setDefaultColorSettings(){
printf("\033[0m") ;
return 0 ;
}
myUI.hpp
#ifndef MYUI_HPP
#define MYUI_HPP
#include
#include "myBigChars.hpp"
#include "myReadkey.hpp"
#include "simpleComputer.hpp"
int ui_initial() ;
int ui_update() ;
int setCurrMemPointer_to_ICounter() ;
int ui_moveCurrMemPointer(keys key) ;
int ui_setMCellValue() ;
int ui_saveMemory() ;
int ui_loadMemory() ;
int ui_setAccumulator() ;
int ui_setICounter() ;
bool checkCorrectInputHEX(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color);
int clearBuffIn() ;
#endif //MYUI_HPP
myUI.cpp
#include "myUI.hpp"
#include "myReadkey.hpp"
int8_t currMemCell = 0 ;
int drawingBoxes() ;
int drawingTexts() ;
int drawingMemory() ;
int drawingAccumulator() ;
int drawingInstructionCounter() ;
int drawingOperation() ;
int drawingFlags() ;
int drawingBigChar() ;
bool checkCorrectInputHEX(const char *buffer) ;
bool checkCorrectInputDEC(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color) ;
/// "Инициализация" интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_initial(){
currMemCell = 0 ;
if (rk_myTermSave())
return -1 ;
sc_memoryInit() ;
sc_accumulator &= (1 << 14) ;
sc_regInit() ;
sc_regSet(IGNORING_TACT_PULSES, true) ;
return 0 ;
}
/// Обновление интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_update(){
mt_clrScreen() ;
if (drawingBoxes())
return -1 ;
if (drawingTexts())
return -1 ;
if (drawingMemory())
return -1 ;
if (drawingAccumulator())
return -1 ;
if (drawingInstructionCounter())
return -1 ;
if (drawingOperation())
return -1 ;
if (drawingFlags())
return -1 ;
if (drawingBigChar())
return -1 ;
mt_gotoXY(1, 23) ;
printf("Input/Output:\n") ;
return 0 ;
}
/// Перемещение выделенной ячейки на значение ICounter
/// \return 0
int setCurrMemPointer_to_ICounter(){
currMemCell = sc_instructionCounter ;
return 0 ;
}
/// Перемещение выделенной ячейки
/// \param key - Клавиша
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_moveCurrMemPointer(keys key){
switch (key) {
case keys::KEY_UP: (currMemCell <= 9) ? (currMemCell = 90 + currMemCell) : (currMemCell -= 10) ; return 0 ;
case keys::KEY_RIGHT: (!((currMemCell + 1) % 10)) ? (currMemCell -= 9) : (currMemCell += 1) ; return 0 ;
case keys::KEY_DOWN: (currMemCell >= 90) ? (currMemCell = currMemCell - 90) : (currMemCell += 10) ; return 0 ;
case keys::KEY_LEFT: (!(currMemCell % 10)) ? (currMemCell += 9) : (currMemCell -= 1) ; return 0 ;
}
return -1 ;
}
int ui_setMCellValue(){
printf("Set the value of the cell under the number \033[38;5;%dm0x%02X\033[0m\n", colors::SOFT_GREEN, currMemCell) ;
printf("Enter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+')
i = 1 ;
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
if (sc_memorySet(currMemCell, res))
return -1 ;
return 0 ;
}
int ui_saveMemory(){
char filename[102] ;
printf("Saving file...\n") ;
printf("Enter the file name to save > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
printf("\033[38;5;%dmThe file name is too long. The length is trimmed to the first 100 characters.\033[0m\n", BLUE) ;
clearBuffIn(); // очистка потока ввода
}
else
filename[strlen(filename) - 1] = '\0' ;
if (sc_memorySave(filename)){
ui_messageOutput((char *)"Failed to save memory", colors::RED) ;
return -1 ;
}
else
ui_messageOutput((char *)"Successful save", colors::GREEN) ;
return 0 ;
}
int ui_loadMemory(){
char filename[102] ;
printf("Loading file...\n") ;
printf("Enter the file name to load > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
ui_messageOutput((char *)"The name of the file to open is too long (up to 100 characters are allowed)", colors::BLUE) ;
clearBuffIn(); // очистка потока ввода
return -1 ;
}
filename[strlen(filename) - 1] = '\0' ;
if (sc_memoryLoad(filename)){
ui_messageOutput((char *)"Failed to load memory", colors::RED) ;
return -1 ;
}
return 0 ;
}
int ui_setAccumulator(){
// может ли в accumulator храниться команда ? (теперь нет)
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"Accumulator\"\033[0m", colors::GREEN) ;
printf("\nEnter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+'){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if(number > 0x3FFF){
ui_messageOutput((char *)"The command value must not exceed 14 bits (0x3FFF)", colors::RED) ;
return -1 ;
}
else
{
number &= 0x3FFF ;
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
else{
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
}
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
sc_accumulator = res ;
return 0 ;
}
int ui_setICounter(){
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"InstructionCounter\"\033[0m between \033[38;5;%dm00\033[0m and \033[38;5;%dm99\033[0m inclusive\n", colors::GREEN, colors::SOFT_GREEN, colors::SOFT_GREEN) ;
printf("Enter value in \033[38;5;%dmDEC\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
if (!checkCorrectInputDEC(buffer)){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(buffer, &tmp, 10);
if(number > 99){
ui_messageOutput((char *)"The value must not exceed the amount of memory", colors::RED) ;
return -1 ;
}
sc_instructionCounter = (uint8_t)number ;
return 0 ;
}
/// Отрисовка "боксов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBoxes(){
if (bc_box(1, 1, 61, 12)) // Окно Memory
return -1 ;
if (bc_box(62, 1, 22, 3)) // Окно accumulator
return -1 ;
if (bc_box(62, 4, 22, 3)) // Окно instructionCounter
return -1 ;
if (bc_box(62, 7, 22, 3)) // Окно Operation
return -1 ;
if (bc_box(62, 10, 22, 3)) // Окно Flags
return -1 ;
if (bc_box(1, 13, 52, 10)) // Окно BigChars
return -1 ;
if (bc_box(53, 13, 31, 10)) // Окно Keys
return -1 ;
return 0 ;
}
/// Отрисовка заголовков и текста
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingTexts(){
/* Заголовки */
mt_gotoXY(30,1) ;
printf(" Memory ") ;
mt_gotoXY(66,1) ;
printf(" accumulator ") ;
mt_gotoXY(63,4) ;
printf(" instructionCounter ") ;
mt_gotoXY(67,7) ;
printf(" Operation ") ;
mt_gotoXY(69,10) ;
printf(" Flags ") ;
mt_gotoXY(54,13) ;
printf(" Keys: ") ;
/* HotKeys */
char* hotK[] = {(char *)"l - load",
(char *)"s - save",
(char *)"r - run",
(char *)"t - step",
(char *)"i - reset",
(char *)"F5 - accumulator",
(char *)"F6 - instructionCounter"};
for (int i = 0 ; i < sizeof(hotK) / sizeof(*hotK) ; ++i) {
mt_gotoXY(54,i + 14) ;
printf("%s", hotK[i]) ;
}
return 0 ;
}
/// Отрисовка памяти
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingMemory(){
for (int i = 0 ; i < 10 ; ++i)
for (int j = 0 ; j < 10 ; ++j) {
mt_gotoXY(2 + (5 * j + j), 2 + i) ;
unsigned short int tmp ;
sc_memoryGet(i * 10 + j, &tmp) ;
if ((i * 10 + j) == currMemCell)
mt_setBGcolor(colors::GREEN) ;
if((tmp >> 14) & 1)
if((tmp >> 13) & 1)
printf("-%04X", (
(tmp - 1)) & 0x3FFF) ;
else
printf(" %04X", tmp & 0x1FFF) ;
else
printf("+%04X", tmp) ;
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка accumulator
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingAccumulator(){
mt_gotoXY(70,2) ;
// bool over ;
// sc_regGet(OVERFLOW, &over) ;
// if (over){
// mt_setFGcolor(colors::PEACH) ;
// printf(" over") ;
// mt_setDefaultColorSettings() ;
// }
// else{
if((sc_accumulator >> 14) & 1)
if((sc_accumulator >> 13) & 1)
printf("-%04X", (
(sc_accumulator - 1)) & 0x3FFF) ;
else
printf(" %04X", sc_accumulator & 0x1FFF) ;
else
printf("+%04X", sc_accumulator) ;
// }
return 0 ;
}
/// Отрисовка Operation
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingOperation(){
mt_gotoXY(69,8) ;
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1)){
unsigned short int operand, command ;
sc_commandDecode(tmp, &command, &operand) ;
printf("+%02X:%02X", command, operand) ;
}
else{
unsigned short int left, right ;
bool negative = (tmp >> 13) & 1 ;
if(negative)
tmp = (
(tmp - 1)) & 0x3FFF ;
else
tmp &= 0x1FFF ;
left = tmp >> 8 ;
right = tmp & 0xFF ;
negative ? printf("-%02X:%02X", left, right) : printf(" %02X:%02X", left, right) ;
}
return 0 ;
}
/// Отрисовка instructionCounter
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingInstructionCounter(){
mt_gotoXY(71,5) ;
// bool over, zero, out, comm ;
// sc_regGet(OVERFLOW, &over) ;
// sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
// sc_regGet(OUT_OF_MEMORY, &out) ;
// sc_regGet(INCORRECT_COMMAND, &comm) ;
// mt_gotoXY(71,5) ;
// if (over || zero || out || comm){
// mt_setFGcolor(colors::SOFT_GREEN) ;
// printf("null") ;
// mt_setDefaultColorSettings() ;
// }
// else
printf("%04X", sc_instructionCounter) ;
return 0 ;
}
/// Отрисовка флагов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingFlags(){
char tmp[] = {'O', 'Z', 'M', 'I', 'C'};
for (int i = 0 ; i < SC_REG_SIZE ; ++i) {
bool value ;
if (sc_regGet(i, &value))
return -1 ;
mt_gotoXY(68 + (i * 2), 11) ;
if (value){
mt_setFGcolor(colors::PEACH) ;
printf("%c", tmp[i]) ;
}
else{
mt_setFGcolor(colors::GRAY) ;
printf("%c", tmp[i]) ;
}
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка "BigChar'ов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBigChar(){
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1))
bc_printBigChar(bc[16], 2, 14, GREEN) ;
else if((tmp >> 13) & 1){
bc_printBigChar(bc[17], 2, 14, GREEN) ;
tmp = (
(tmp - 1)) & 0x3FFF;
}
else
tmp &= 0x3FFF ;
for (int i = 0; i < 4; ++i) {
int ch = (tmp & ( 0xF << (4 * (3 - i)) )) >> (4 * (3 - i)) ;
bc_printBigChar(bc[ch], 2 + 8 * (i + 1) + 2 * (i + 1), 14, GREEN) ;
}
return 0 ;
}
bool checkCorrectInputHEX(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 4)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isxdigit(buffer[i])))
return false ;
return true ;
}
bool checkCorrectInputDEC(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 5)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isdigit(buffer[i])))
return false ;
return true ;
}
int ui_messageOutput(char *str, enum colors color){
printf("\033[38;5;%dm%s\033[0m", color, str) ;
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
return 0 ;
}
int clearBuffIn(){
int c;
do {
c = getchar();
} while (c != '\n' && c != '\0');
return 0 ;
}
myReadkey.hpp
#ifndef MYREADKEY_HPP
#define MYREADKEY_HPP
#include
#include
#include
extern termios save;
enum keys
{
KEY_L,
KEY_S,
KEY_R,
KEY_T,
KEY_I,
KEY_F5,
KEY_F6 ,
KEY_UP,
KEY_DOWN,
KEY_RIGHT,
KEY_LEFT,
KEY_ESC,
KEY_ENTER,
KEY_OTHER,
};
int rk_readKey(enum keys *key) ;
int rk_myTermSave() ;
int rk_myTermRestore() ;
int rk_myTermRegime (bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint) ;
#endif //MYREADKEY_HPP
myReadkey.cpp
#include "myReadkey.hpp"
termios save;
/// Возвращающую первую клавишу, которую нажал пользователь
/// \param key - Адрес переменной, в которую возвращается номер нажатой клавиши
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_readKey (enum keys * key){
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
rk_myTermRestore() ;
if (buffer[0] == '\033')
if (buffer[1] == '\0')
*key = KEY_ESC ;
else if (buffer[1] == '[')
if (buffer[2] == 'A' and buffer[3] == '\0')
*key = KEY_UP ;
else if (buffer[2] == 'B' and buffer[3] == '\0')
*key = KEY_DOWN ;
else if (buffer[2] == 'C' and buffer[3] == '\0')
*key = KEY_RIGHT ;
else if (buffer[2] == 'D' and buffer[3] == '\0')
*key = KEY_LEFT ;
else if (buffer[2] == '1' and buffer[3] == '5')
*key = KEY_F5 ;
else if (buffer[2] == '1' and buffer[3] == '7')
*key = KEY_F6 ;
else
*key = KEY_OTHER ;
else
*key = KEY_OTHER ;
else if (buffer[0] == '\n' and buffer[1] == '\0')
*key = KEY_ENTER ;
else
if ((buffer[0] == 'l' or buffer[0] == 'L') and buffer[1] == '\0')
*key = KEY_L ;
else if ((buffer[0] == 's' or buffer[0] == 'S') and buffer[1] == '\0')
*key = KEY_S ;
else if ((buffer[0] == 'r' or buffer[0] == 'R') and buffer[1] == '\0')
*key = KEY_R ;
else if ((buffer[0] == 't' or buffer[0] == 'T') and buffer[1] == '\0')
*key = KEY_T ;
else if ((buffer[0] == 'i' or buffer[0] == 'I') and buffer[1] == '\0')
*key = KEY_I ;
else
*key = KEY_OTHER ;
return 0 ;
}
/// Функция, сохраняющая текущие параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermSave(){
if (tcgetattr(fileno(stdin), &save))
return -1 ;
return 0 ;
}
/// Функция, восстанавливающая сохраненные параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRestore(){
tcsetattr(fileno(stdin), TCSAFLUSH, &save) ;
return 0 ;
}
/// Функция, переключающая режим работы терминала (канонический / неканонический)
/// \param regime
/// \param vtime
/// \param vmin
/// \param echo
/// \param sigint
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRegime(bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint){
termios curr{} ;
tcgetattr(fileno(stdin), &curr) ;
if(regime)
curr.c_lflag |= ICANON ;
else{
curr.c_lflag &=
ICANON ;
sigint ? (curr.c_lflag |= ISIG) : (curr.c_lflag &=
ISIG) ;
echo ? (curr.c_lflag |= ECHO) : (curr.c_lflag &=
ECHO) ;
Приложение. Листинг
Makefile
d.PHONY: all clean run
COMPILER := g++
FLAGS := -fdiagnostics-color=always -Werror -MMD
SRC_SC := src/sc
BUILD_SC := build/sc
LIBS_SC := libs/sc
SRC_SA := src/sa
BUILD_SA := build/sa
SRC_SB := src/sb
BUILD_SB := build/sb
BIN := bin
SC := simpleComputer
SA := simpleAssembler
SB := simpleBasic
all: create $(BIN)/$(SC) $(BIN)/$(SA) $(BIN)/$(SB)
-include $((BUILD_SC)/*.d
-include $((BUILD_SA)/*.d
-include $((BUILD_SB)/*.d
sc: create $(BIN)/$(SC)
run_sc: sc
./$(BIN)/$(SC)
$(BIN)/$(SC): $(LIBS_SC)/libsimpleComputer.a $(LIBS_SC)/libmyTerm.a $(LIBS_SC)/libmyBigChars.a $(LIBS_SC)/libmyReadkey.a $(LIBS_SC)/libmyUI.a $(LIBS_SC)/libmyALU.a $(LIBS_SC)/libmyCU.a $(BUILD_SC)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SC) $(BUILD_SC)/main.o -L $(LIBS_SC) -lsimpleComputer -lmyUI -lmyTerm -lmyBigChars -lmyReadkey -lmyCU -lmyALU
$(BUILD_SC)/%.o: $(SRC_SC)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
$(LIBS_SC)/libsimpleComputer.a: $(BUILD_SC)/simpleComputer.o
ar cr $@ $^
$(LIBS_SC)/libmyTerm.a: $(BUILD_SC)/myTerm.o
ar cr $@ $^
$(LIBS_SC)/libmyBigChars.a: $(BUILD_SC)/myBigChars.o
ar cr $@ $^
$(LIBS_SC)/libmyReadkey.a: $(BUILD_SC)/myReadkey.o
ar cr $@ $^
$(LIBS_SC)/libmyUI.a: $(BUILD_SC)/myUI.o
ar cr $@ $^
$(LIBS_SC)/libmyALU.a: $(BUILD_SC)/myALU.o
ar cr $@ $^
$(LIBS_SC)/libmyCU.a: $(BUILD_SC)/myCU.o
ar cr $@ $^
sa: create $(BIN)/$(SA)
run_sa: create $(BIN)/$(SA)
./$(BIN)/$(SA)
$(BIN)/$(SA): $(BUILD_SA)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SA) $(BUILD_SA)/main.o
$(BUILD_SA)/%.o: $(SRC_SA)/%.cpps
$(COMPILER) $(FLAGS) -c $^ -o $@
sb: create $(BIN)/$(SB)
run_sb: create $(BIN)/$(SB)
./$(BIN)/$(SB)
$(BIN)/$(SB): $(BUILD_SB)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SB) $(BUILD_SB)/main.o
$(BUILD_SB)/%.o: $(SRC_SB)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
create:
mkdir -p $(BUILD_SC) $(BUILD_SA) $(BUILD_SB) $(LIBS_SC) $(BIN)
clean:
@rm -rf build libs $(BIN)
SimpleComputer
main.cpp
#include
#include "simpleComputer.hpp"
#include "myUI.hpp"
#include "myReadkey.hpp"
#include "myCU.hpp"
void signalHandler(int signal) ;
#include
int main(int argc, char const *argv[]){
ui_initial() ;
signal(SIGALRM, signalHandler) ;
signal(SIGUSR1, signalHandler) ;
bool zero, out, ignor, comm ;
keys key;
if (argc == 2){
sc_memoryLoad((char *)argv[1]) ;
}
else if (argc > 2){
ui_messageOutput((char *)"Exceeded the number of arguments", colors::RED) ;
return -1 ;
}
do {
sc_regGet(IGNORING_TACT_PULSES, &ignor);
ui_update() ;
rk_readKey(&key);
if (ignor){
sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
sc_regGet(OUT_OF_MEMORY, &out) ;
sc_regGet(INCORRECT_COMMAND, &comm) ;
if (zero || out || comm){
switch(key){
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
}
}
else{
switch(key){
case keys::KEY_UP:
ui_moveCurrMemPointer(keys::KEY_UP) ;
break ;
case keys::KEY_RIGHT:
ui_moveCurrMemPointer(keys::KEY_RIGHT) ;
break ;
case keys::KEY_DOWN:
ui_moveCurrMemPointer(keys::KEY_DOWN) ;
break ;
case keys::KEY_LEFT:
ui_moveCurrMemPointer(keys::KEY_LEFT) ;
break ;
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_R:
sc_regInit() ;
raise(SIGALRM) ;
break ;
case keys::KEY_T:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
CU() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
case keys::KEY_F5:
ui_setAccumulator() ;
break ;
case keys::KEY_F6:
ui_setICounter() ;
break ;
case keys::KEY_ENTER:
ui_setMCellValue() ;
break ;
}
}
}
else
if (key == keys::KEY_I)
raise(SIGUSR1) ;
} while(key != keys::KEY_ESC) ;
return 0 ;
}
void signalHandler(int signal){
switch (signal) {
case SIGALRM:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
if (CU()){
sc_regSet(IGNORING_TACT_PULSES, true);
ui_update() ;
alarm(0) ;
}
else
alarm(1) ;
rk_myTermRegime(false, 0, 0, false, false) ;
break ;
case SIGUSR1:
alarm(0) ;
ui_initial() ;
break ;
default:
break ;
}
}
simpleComputer.hpp
#ifndef SIMPLECOMPUTER_HPP
#define SIMPLECOMPUTER_HPP
#include
#define OVERFLOW 0 // Переполнение при выполнении операции
#define DIVISION_ERR_BY_ZERO 1 // Ошибка деления на 0
#define OUT_OF_MEMORY 2 // Ошибка выхода за границы памяти
#define IGNORING_TACT_PULSES 3 // Игнорирование тактовых импульсов
#define INCORRECT_COMMAND 4 // Указана неверная команда
const short int SC_REG_SIZE = 5 ;
const short int SC_MEM_SIZE = 100 ;
extern unsigned short int sc_accumulator ;
extern uint8_t sc_instructionCounter ;
int sc_memoryInit () ;
int sc_memorySet (unsigned short int address, unsigned short int value) ;
int sc_memoryGet (unsigned short int address, unsigned short int * value) ;
int sc_memorySave (char* filename) ;
int sc_memoryLoad (char* filename) ;
int sc_regInit () ;
int sc_regSet (int8_t reg, bool value) ;
int sc_regGet (int8_t reg, bool * value) ;
int sc_commandEncode (unsigned short int command, unsigned short int operand, unsigned short int * value) ;
int sc_commandDecode (unsigned short int value, unsigned short int * command, unsigned short int * operand) ;
#endif //SIMPLECOMPUTER_HPP
simpleComputer.cpp
#include "simpleComputer.hpp"
unsigned short int sc_memory[SC_MEM_SIZE] ;
uint8_t sc_regFLAGS ;
unsigned short int sc_accumulator ;
uint8_t sc_instructionCounter ;
/// Инициализирует оперативную память SC, задавая всем её ячейкам нулевые значения
/// \return 0
int sc_memoryInit()
{
sc_instructionCounter = 0 ;
for (unsigned short & mem : sc_memory)
mem = 0 ;
return 0 ;
}
/// Задает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySet(unsigned short int address, unsigned short int value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_memory[address] = value ;
return 0 ;
}
/// Возвращает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryGet(unsigned short int address, unsigned short int * value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
*value = sc_memory[address] ;
return 0 ;
}
/// Сохраняет содержимое памяти в файл в бинарном виде
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySave(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "wb"))){
return -1 ;
}
fwrite(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Загружает из указанного файла содержимое оперативной памяти
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryLoad(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "rb"))){
return -1 ;
}
fread(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Инициализирует регистр флагов нулевым значением
/// \return 0
int sc_regInit(){
sc_regFLAGS = 0 ;
return 0 ;
}
/// Устанавливает значение указанного регистра флагов
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regSet(int8_t reg, bool value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
value == 1 ? (sc_regFLAGS |= (1 << reg)) : (sc_regFLAGS &=
(1 << reg)) ;
return 0 ;
}
/// Возвращает значение указанного флага
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regGet(int8_t reg, bool *value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
*value = sc_regFLAGS & (1 << reg) ;
return 0 ;
}
/// Кодирует команду с указанным номером и операндом и помещает результат в value
/// \param command - команда
/// \param operand - операнд
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandEncode(unsigned short int command, unsigned short int operand, unsigned short int * value){
if (command > 0x7F)
return -1 ;
if (operand > 0x7F)
return -1 ;
* value = 0 ;
/* Операнд */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (operand >> i) & 1 ;
*value |= (bit << i) ;
}
/* Команда */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (command >> i) & 1 ;
*value |= (bit << (i + 7)) ;
}
return 0 ;
}
/// Декодирует значение как команду SС
/// \param value - значение
/// \param command - команда
/// \param operand - операнд
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandDecode(unsigned short int value, unsigned short int * command, unsigned short int * operand){
int tmpCom = 0, tmpOp = 0 ;
if ((value >> 14) & 1){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> i) & 1 ;
tmpOp |= (bit << i) ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> (i + 7)) & 1 ;
tmpCom |= (bit << i) ;
}
* command = tmpCom ;
* operand = tmpOp ;
return 0 ;
}
myTerm.hpp
#ifndef MYTERM_HPP
#define MYTERM_HPP
#include
#include
enum colors {
RED = 196,
PEACH = 203,
GREEN = 10,
SOFT_GREEN =192,
BLUE = 20,
BLACK = 16,
GRAY = 240,
WHITE = 15,
DEFAULT = 0};
int mt_clrScreen () ;
int mt_gotoXY(unsigned int col,unsigned int row) ;
int mt_getScreenSize(unsigned int *rows, unsigned int* cols) ;
int mt_setFGcolor(enum colors color) ;
int mt_setBGcolor(enum colors color) ;
int mt_setDefaultColorSettings() ;
#endif //MYTERM_HPP
myTerm.cpp
#include "myTerm.hpp"
/// Производит очистку и перемещение курсора в левый верхний угол экрана
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_clrScreen (){
printf("\033[H\033[2J") ;
return 0 ;
}
/// Перемещает курсор в указанную позицию
/// \param col - столбец
/// \param row - строка
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_gotoXY(unsigned int col, unsigned int row)
{
unsigned int rows, cols ;
if (mt_getScreenSize(&rows, &cols) == -1)
return -1 ;
if ((row > rows) || (row <= 0)||(col > cols) || (col <= 0))
return -1 ;
printf("\033[%d;%dH", row, col) ;
return 0 ;
}
/// Определяет размер экрана терминала
/// \param rows - кол-во строк
/// \param cols - кол-во столбцов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_getScreenSize(unsigned int *rows, unsigned int *cols){
winsize ws{} ;
if (ioctl(1, TIOCGWINSZ, &ws))
return -1 ;
* rows = ws.ws_row ;
* cols = ws.ws_col ;
return 0 ;
}
/// Устанавливает цвет последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setFGcolor(enum colors color){
printf("\033[38;5;%dm",color) ;
return 0 ;
}
/// Устанавливает цвет фона последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setBGcolor(enum colors color){
printf("\033[48;5;%dm",color) ;
return 0 ;
}
/// Возвращает цвета в стандартное состояние
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setDefaultColorSettings(){
printf("\033[0m") ;
return 0 ;
}
myUI.hpp
#ifndef MYUI_HPP
#define MYUI_HPP
#include
#include "myBigChars.hpp"
#include "myReadkey.hpp"
#include "simpleComputer.hpp"
int ui_initial() ;
int ui_update() ;
int setCurrMemPointer_to_ICounter() ;
int ui_moveCurrMemPointer(keys key) ;
int ui_setMCellValue() ;
int ui_saveMemory() ;
int ui_loadMemory() ;
int ui_setAccumulator() ;
int ui_setICounter() ;
bool checkCorrectInputHEX(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color);
int clearBuffIn() ;
#endif //MYUI_HPP
myUI.cpp
#include "myUI.hpp"
#include "myReadkey.hpp"
int8_t currMemCell = 0 ;
int drawingBoxes() ;
int drawingTexts() ;
int drawingMemory() ;
int drawingAccumulator() ;
int drawingInstructionCounter() ;
int drawingOperation() ;
int drawingFlags() ;
int drawingBigChar() ;
bool checkCorrectInputHEX(const char *buffer) ;
bool checkCorrectInputDEC(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color) ;
/// "Инициализация" интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_initial(){
currMemCell = 0 ;
if (rk_myTermSave())
return -1 ;
sc_memoryInit() ;
sc_accumulator &= (1 << 14) ;
sc_regInit() ;
sc_regSet(IGNORING_TACT_PULSES, true) ;
return 0 ;
}
/// Обновление интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_update(){
mt_clrScreen() ;
if (drawingBoxes())
return -1 ;
if (drawingTexts())
return -1 ;
if (drawingMemory())
return -1 ;
if (drawingAccumulator())
return -1 ;
if (drawingInstructionCounter())
return -1 ;
if (drawingOperation())
return -1 ;
if (drawingFlags())
return -1 ;
if (drawingBigChar())
return -1 ;
mt_gotoXY(1, 23) ;
printf("Input/Output:\n") ;
return 0 ;
}
/// Перемещение выделенной ячейки на значение ICounter
/// \return 0
int setCurrMemPointer_to_ICounter(){
currMemCell = sc_instructionCounter ;
return 0 ;
}
/// Перемещение выделенной ячейки
/// \param key - Клавиша
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_moveCurrMemPointer(keys key){
switch (key) {
case keys::KEY_UP: (currMemCell <= 9) ? (currMemCell = 90 + currMemCell) : (currMemCell -= 10) ; return 0 ;
case keys::KEY_RIGHT: (!((currMemCell + 1) % 10)) ? (currMemCell -= 9) : (currMemCell += 1) ; return 0 ;
case keys::KEY_DOWN: (currMemCell >= 90) ? (currMemCell = currMemCell - 90) : (currMemCell += 10) ; return 0 ;
case keys::KEY_LEFT: (!(currMemCell % 10)) ? (currMemCell += 9) : (currMemCell -= 1) ; return 0 ;
}
return -1 ;
}
int ui_setMCellValue(){
printf("Set the value of the cell under the number \033[38;5;%dm0x%02X\033[0m\n", colors::SOFT_GREEN, currMemCell) ;
printf("Enter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+')
i = 1 ;
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
if (sc_memorySet(currMemCell, res))
return -1 ;
return 0 ;
}
int ui_saveMemory(){
char filename[102] ;
printf("Saving file...\n") ;
printf("Enter the file name to save > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
printf("\033[38;5;%dmThe file name is too long. The length is trimmed to the first 100 characters.\033[0m\n", BLUE) ;
clearBuffIn(); // очистка потока ввода
}
else
filename[strlen(filename) - 1] = '\0' ;
if (sc_memorySave(filename)){
ui_messageOutput((char *)"Failed to save memory", colors::RED) ;
return -1 ;
}
else
ui_messageOutput((char *)"Successful save", colors::GREEN) ;
return 0 ;
}
int ui_loadMemory(){
char filename[102] ;
printf("Loading file...\n") ;
printf("Enter the file name to load > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
ui_messageOutput((char *)"The name of the file to open is too long (up to 100 characters are allowed)", colors::BLUE) ;
clearBuffIn(); // очистка потока ввода
return -1 ;
}
filename[strlen(filename) - 1] = '\0' ;
if (sc_memoryLoad(filename)){
ui_messageOutput((char *)"Failed to load memory", colors::RED) ;
return -1 ;
}
return 0 ;
}
int ui_setAccumulator(){
// может ли в accumulator храниться команда ? (теперь нет)
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"Accumulator\"\033[0m", colors::GREEN) ;
printf("\nEnter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+'){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if(number > 0x3FFF){
ui_messageOutput((char *)"The command value must not exceed 14 bits (0x3FFF)", colors::RED) ;
return -1 ;
}
else
{
number &= 0x3FFF ;
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
else{
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
}
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
sc_accumulator = res ;
return 0 ;
}
int ui_setICounter(){
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"InstructionCounter\"\033[0m between \033[38;5;%dm00\033[0m and \033[38;5;%dm99\033[0m inclusive\n", colors::GREEN, colors::SOFT_GREEN, colors::SOFT_GREEN) ;
printf("Enter value in \033[38;5;%dmDEC\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
if (!checkCorrectInputDEC(buffer)){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(buffer, &tmp, 10);
if(number > 99){
ui_messageOutput((char *)"The value must not exceed the amount of memory", colors::RED) ;
return -1 ;
}
sc_instructionCounter = (uint8_t)number ;
return 0 ;
}
/// Отрисовка "боксов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBoxes(){
if (bc_box(1, 1, 61, 12)) // Окно Memory
return -1 ;
if (bc_box(62, 1, 22, 3)) // Окно accumulator
return -1 ;
if (bc_box(62, 4, 22, 3)) // Окно instructionCounter
return -1 ;
if (bc_box(62, 7, 22, 3)) // Окно Operation
return -1 ;
if (bc_box(62, 10, 22, 3)) // Окно Flags
return -1 ;
if (bc_box(1, 13, 52, 10)) // Окно BigChars
return -1 ;
if (bc_box(53, 13, 31, 10)) // Окно Keys
return -1 ;
return 0 ;
}
/// Отрисовка заголовков и текста
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingTexts(){
/* Заголовки */
mt_gotoXY(30,1) ;
printf(" Memory ") ;
mt_gotoXY(66,1) ;
printf(" accumulator ") ;
mt_gotoXY(63,4) ;
printf(" instructionCounter ") ;
mt_gotoXY(67,7) ;
printf(" Operation ") ;
mt_gotoXY(69,10) ;
printf(" Flags ") ;
mt_gotoXY(54,13) ;
printf(" Keys: ") ;
/* HotKeys */
char* hotK[] = {(char *)"l - load",
(char *)"s - save",
(char *)"r - run",
(char *)"t - step",
(char *)"i - reset",
(char *)"F5 - accumulator",
(char *)"F6 - instructionCounter"};
for (int i = 0 ; i < sizeof(hotK) / sizeof(*hotK) ; ++i) {
mt_gotoXY(54,i + 14) ;
printf("%s", hotK[i]) ;
}
return 0 ;
}
/// Отрисовка памяти
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingMemory(){
for (int i = 0 ; i < 10 ; ++i)
for (int j = 0 ; j < 10 ; ++j) {
mt_gotoXY(2 + (5 * j + j), 2 + i) ;
unsigned short int tmp ;
sc_memoryGet(i * 10 + j, &tmp) ;
if ((i * 10 + j) == currMemCell)
mt_setBGcolor(colors::GREEN) ;
if((tmp >> 14) & 1)
if((tmp >> 13) & 1)
printf("-%04X", (
(tmp - 1)) & 0x3FFF) ;
else
printf(" %04X", tmp & 0x1FFF) ;
else
printf("+%04X", tmp) ;
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка accumulator
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingAccumulator(){
mt_gotoXY(70,2) ;
// bool over ;
// sc_regGet(OVERFLOW, &over) ;
// if (over){
// mt_setFGcolor(colors::PEACH) ;
// printf(" over") ;
// mt_setDefaultColorSettings() ;
// }
// else{
if((sc_accumulator >> 14) & 1)
if((sc_accumulator >> 13) & 1)
printf("-%04X", (
(sc_accumulator - 1)) & 0x3FFF) ;
else
printf(" %04X", sc_accumulator & 0x1FFF) ;
else
printf("+%04X", sc_accumulator) ;
// }
return 0 ;
}
/// Отрисовка Operation
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingOperation(){
mt_gotoXY(69,8) ;
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1)){
unsigned short int operand, command ;
sc_commandDecode(tmp, &command, &operand) ;
printf("+%02X:%02X", command, operand) ;
}
else{
unsigned short int left, right ;
bool negative = (tmp >> 13) & 1 ;
if(negative)
tmp = (
(tmp - 1)) & 0x3FFF ;
else
tmp &= 0x1FFF ;
left = tmp >> 8 ;
right = tmp & 0xFF ;
negative ? printf("-%02X:%02X", left, right) : printf(" %02X:%02X", left, right) ;
}
return 0 ;
}
/// Отрисовка instructionCounter
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingInstructionCounter(){
mt_gotoXY(71,5) ;
// bool over, zero, out, comm ;
// sc_regGet(OVERFLOW, &over) ;
// sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
// sc_regGet(OUT_OF_MEMORY, &out) ;
// sc_regGet(INCORRECT_COMMAND, &comm) ;
// mt_gotoXY(71,5) ;
// if (over || zero || out || comm){
// mt_setFGcolor(colors::SOFT_GREEN) ;
// printf("null") ;
// mt_setDefaultColorSettings() ;
// }
// else
printf("%04X", sc_instructionCounter) ;
return 0 ;
}
/// Отрисовка флагов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingFlags(){
char tmp[] = {'O', 'Z', 'M', 'I', 'C'};
for (int i = 0 ; i < SC_REG_SIZE ; ++i) {
bool value ;
if (sc_regGet(i, &value))
return -1 ;
mt_gotoXY(68 + (i * 2), 11) ;
if (value){
mt_setFGcolor(colors::PEACH) ;
printf("%c", tmp[i]) ;
}
else{
mt_setFGcolor(colors::GRAY) ;
printf("%c", tmp[i]) ;
}
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка "BigChar'ов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBigChar(){
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1))
bc_printBigChar(bc[16], 2, 14, GREEN) ;
else if((tmp >> 13) & 1){
bc_printBigChar(bc[17], 2, 14, GREEN) ;
tmp = (
(tmp - 1)) & 0x3FFF;
}
else
tmp &= 0x3FFF ;
for (int i = 0; i < 4; ++i) {
int ch = (tmp & ( 0xF << (4 * (3 - i)) )) >> (4 * (3 - i)) ;
bc_printBigChar(bc[ch], 2 + 8 * (i + 1) + 2 * (i + 1), 14, GREEN) ;
}
return 0 ;
}
bool checkCorrectInputHEX(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 4)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isxdigit(buffer[i])))
return false ;
return true ;
}
bool checkCorrectInputDEC(const char *buffer){
if (strlen(buffer) == 0 or strlen(buffer) > 5)
return false ;
for (int i = 0 ; i < strlen(buffer) ; ++i)
if (!(isdigit(buffer[i])))
return false ;
return true ;
}
int ui_messageOutput(char *str, enum colors color){
printf("\033[38;5;%dm%s\033[0m", color, str) ;
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
return 0 ;
}
int clearBuffIn(){
int c;
do {
c = getchar();
} while (c != '\n' && c != '\0');
return 0 ;
}
myReadkey.hpp
#ifndef MYREADKEY_HPP
#define MYREADKEY_HPP
#include
#include
#include
extern termios save;
enum keys
{
KEY_L,
KEY_S,
KEY_R,
KEY_T,
KEY_I,
KEY_F5,
KEY_F6 ,
KEY_UP,
KEY_DOWN,
KEY_RIGHT,
KEY_LEFT,
KEY_ESC,
KEY_ENTER,
KEY_OTHER,
};
int rk_readKey(enum keys *key) ;
int rk_myTermSave() ;
int rk_myTermRestore() ;
int rk_myTermRegime (bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint) ;
#endif //MYREADKEY_HPP
myReadkey.cpp
#include "myReadkey.hpp"
termios save;
/// Возвращающую первую клавишу, которую нажал пользователь
/// \param key - Адрес переменной, в которую возвращается номер нажатой клавиши
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_readKey (enum keys * key){
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
rk_myTermRestore() ;
if (buffer[0] == '\033')
if (buffer[1] == '\0')
*key = KEY_ESC ;
else if (buffer[1] == '[')
if (buffer[2] == 'A' and buffer[3] == '\0')
*key = KEY_UP ;
else if (buffer[2] == 'B' and buffer[3] == '\0')
*key = KEY_DOWN ;
else if (buffer[2] == 'C' and buffer[3] == '\0')
*key = KEY_RIGHT ;
else if (buffer[2] == 'D' and buffer[3] == '\0')
*key = KEY_LEFT ;
else if (buffer[2] == '1' and buffer[3] == '5')
*key = KEY_F5 ;
else if (buffer[2] == '1' and buffer[3] == '7')
*key = KEY_F6 ;
else
*key = KEY_OTHER ;
else
*key = KEY_OTHER ;
else if (buffer[0] == '\n' and buffer[1] == '\0')
*key = KEY_ENTER ;
else
if ((buffer[0] == 'l' or buffer[0] == 'L') and buffer[1] == '\0')
*key = KEY_L ;
else if ((buffer[0] == 's' or buffer[0] == 'S') and buffer[1] == '\0')
*key = KEY_S ;
else if ((buffer[0] == 'r' or buffer[0] == 'R') and buffer[1] == '\0')
*key = KEY_R ;
else if ((buffer[0] == 't' or buffer[0] == 'T') and buffer[1] == '\0')
*key = KEY_T ;
else if ((buffer[0] == 'i' or buffer[0] == 'I') and buffer[1] == '\0')
*key = KEY_I ;
else
*key = KEY_OTHER ;
return 0 ;
}
/// Функция, сохраняющая текущие параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermSave(){
if (tcgetattr(fileno(stdin), &save))
return -1 ;
return 0 ;
}
/// Функция, восстанавливающая сохраненные параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRestore(){
tcsetattr(fileno(stdin), TCSAFLUSH, &save) ;
return 0 ;
}
/// Функция, переключающая режим работы терминала (канонический / неканонический)
/// \param regime
/// \param vtime
/// \param vmin
/// \param echo
/// \param sigint
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRegime(bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint){
termios curr{} ;
tcgetattr(fileno(stdin), &curr) ;
if(regime)
curr.c_lflag |= ICANON ;
else{
curr.c_lflag &=
ICANON ;
Приложение. Листинг
Makefile
d.PHONY: all clean run
COMPILER := g++
FLAGS := -fdiagnostics-color=always -Werror -MMD
SRC_SC := src/sc
BUILD_SC := build/sc
LIBS_SC := libs/sc
SRC_SA := src/sa
BUILD_SA := build/sa
SRC_SB := src/sb
BUILD_SB := build/sb
BIN := bin
SC := simpleComputer
SA := simpleAssembler
SB := simpleBasic
all: create $(BIN)/$(SC) $(BIN)/$(SA) $(BIN)/$(SB)
-include $((BUILD_SC)/*.d
-include $((BUILD_SA)/*.d
-include $((BUILD_SB)/*.d
sc: create $(BIN)/$(SC)
run_sc: sc
./$(BIN)/$(SC)
$(BIN)/$(SC): $(LIBS_SC)/libsimpleComputer.a $(LIBS_SC)/libmyTerm.a $(LIBS_SC)/libmyBigChars.a $(LIBS_SC)/libmyReadkey.a $(LIBS_SC)/libmyUI.a $(LIBS_SC)/libmyALU.a $(LIBS_SC)/libmyCU.a $(BUILD_SC)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SC) $(BUILD_SC)/main.o -L $(LIBS_SC) -lsimpleComputer -lmyUI -lmyTerm -lmyBigChars -lmyReadkey -lmyCU -lmyALU
$(BUILD_SC)/%.o: $(SRC_SC)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
$(LIBS_SC)/libsimpleComputer.a: $(BUILD_SC)/simpleComputer.o
ar cr $@ $^
$(LIBS_SC)/libmyTerm.a: $(BUILD_SC)/myTerm.o
ar cr $@ $^
$(LIBS_SC)/libmyBigChars.a: $(BUILD_SC)/myBigChars.o
ar cr $@ $^
$(LIBS_SC)/libmyReadkey.a: $(BUILD_SC)/myReadkey.o
ar cr $@ $^
$(LIBS_SC)/libmyUI.a: $(BUILD_SC)/myUI.o
ar cr $@ $^
$(LIBS_SC)/libmyALU.a: $(BUILD_SC)/myALU.o
ar cr $@ $^
$(LIBS_SC)/libmyCU.a: $(BUILD_SC)/myCU.o
ar cr $@ $^
sa: create $(BIN)/$(SA)
run_sa: create $(BIN)/$(SA)
./$(BIN)/$(SA)
$(BIN)/$(SA): $(BUILD_SA)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SA) $(BUILD_SA)/main.o
$(BUILD_SA)/%.o: $(SRC_SA)/%.cpps
$(COMPILER) $(FLAGS) -c $^ -o $@
sb: create $(BIN)/$(SB)
run_sb: create $(BIN)/$(SB)
./$(BIN)/$(SB)
$(BIN)/$(SB): $(BUILD_SB)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SB) $(BUILD_SB)/main.o
$(BUILD_SB)/%.o: $(SRC_SB)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
create:
mkdir -p $(BUILD_SC) $(BUILD_SA) $(BUILD_SB) $(LIBS_SC) $(BIN)
clean:
@rm -rf build libs $(BIN)
SimpleComputer
main.cpp
#include
#include "simpleComputer.hpp"
#include "myUI.hpp"
#include "myReadkey.hpp"
#include "myCU.hpp"
void signalHandler(int signal) ;
#include
int main(int argc, char const *argv[]){
ui_initial() ;
signal(SIGALRM, signalHandler) ;
signal(SIGUSR1, signalHandler) ;
bool zero, out, ignor, comm ;
keys key;
if (argc == 2){
sc_memoryLoad((char *)argv[1]) ;
}
else if (argc > 2){
ui_messageOutput((char *)"Exceeded the number of arguments", colors::RED) ;
return -1 ;
}
do {
sc_regGet(IGNORING_TACT_PULSES, &ignor);
ui_update() ;
rk_readKey(&key);
if (ignor){
sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
sc_regGet(OUT_OF_MEMORY, &out) ;
sc_regGet(INCORRECT_COMMAND, &comm) ;
if (zero || out || comm){
switch(key){
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
}
}
else{
switch(key){
case keys::KEY_UP:
ui_moveCurrMemPointer(keys::KEY_UP) ;
break ;
case keys::KEY_RIGHT:
ui_moveCurrMemPointer(keys::KEY_RIGHT) ;
break ;
case keys::KEY_DOWN:
ui_moveCurrMemPointer(keys::KEY_DOWN) ;
break ;
case keys::KEY_LEFT:
ui_moveCurrMemPointer(keys::KEY_LEFT) ;
break ;
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_R:
sc_regInit() ;
raise(SIGALRM) ;
break ;
case keys::KEY_T:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
CU() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
case keys::KEY_F5:
ui_setAccumulator() ;
break ;
case keys::KEY_F6:
ui_setICounter() ;
break ;
case keys::KEY_ENTER:
ui_setMCellValue() ;
break ;
}
}
}
else
if (key == keys::KEY_I)
raise(SIGUSR1) ;
} while(key != keys::KEY_ESC) ;
return 0 ;
}
void signalHandler(int signal){
switch (signal) {
case SIGALRM:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
if (CU()){
sc_regSet(IGNORING_TACT_PULSES, true);
ui_update() ;
alarm(0) ;
}
else
alarm(1) ;
rk_myTermRegime(false, 0, 0, false, false) ;
break ;
case SIGUSR1:
alarm(0) ;
ui_initial() ;
break ;
default:
break ;
}
}
simpleComputer.hpp
#ifndef SIMPLECOMPUTER_HPP
#define SIMPLECOMPUTER_HPP
#include
#define OVERFLOW 0 // Переполнение при выполнении операции
#define DIVISION_ERR_BY_ZERO 1 // Ошибка деления на 0
#define OUT_OF_MEMORY 2 // Ошибка выхода за границы памяти
#define IGNORING_TACT_PULSES 3 // Игнорирование тактовых импульсов
#define INCORRECT_COMMAND 4 // Указана неверная команда
const short int SC_REG_SIZE = 5 ;
const short int SC_MEM_SIZE = 100 ;
extern unsigned short int sc_accumulator ;
extern uint8_t sc_instructionCounter ;
int sc_memoryInit () ;
int sc_memorySet (unsigned short int address, unsigned short int value) ;
int sc_memoryGet (unsigned short int address, unsigned short int * value) ;
int sc_memorySave (char* filename) ;
int sc_memoryLoad (char* filename) ;
int sc_regInit () ;
int sc_regSet (int8_t reg, bool value) ;
int sc_regGet (int8_t reg, bool * value) ;
int sc_commandEncode (unsigned short int command, unsigned short int operand, unsigned short int * value) ;
int sc_commandDecode (unsigned short int value, unsigned short int * command, unsigned short int * operand) ;
#endif //SIMPLECOMPUTER_HPP
simpleComputer.cpp
#include "simpleComputer.hpp"
unsigned short int sc_memory[SC_MEM_SIZE] ;
uint8_t sc_regFLAGS ;
unsigned short int sc_accumulator ;
uint8_t sc_instructionCounter ;
/// Инициализирует оперативную память SC, задавая всем её ячейкам нулевые значения
/// \return 0
int sc_memoryInit()
{
sc_instructionCounter = 0 ;
for (unsigned short & mem : sc_memory)
mem = 0 ;
return 0 ;
}
/// Задает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySet(unsigned short int address, unsigned short int value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_memory[address] = value ;
return 0 ;
}
/// Возвращает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryGet(unsigned short int address, unsigned short int * value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
*value = sc_memory[address] ;
return 0 ;
}
/// Сохраняет содержимое памяти в файл в бинарном виде
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySave(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "wb"))){
return -1 ;
}
fwrite(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Загружает из указанного файла содержимое оперативной памяти
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryLoad(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "rb"))){
return -1 ;
}
fread(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Инициализирует регистр флагов нулевым значением
/// \return 0
int sc_regInit(){
sc_regFLAGS = 0 ;
return 0 ;
}
/// Устанавливает значение указанного регистра флагов
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regSet(int8_t reg, bool value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
value == 1 ? (sc_regFLAGS |= (1 << reg)) : (sc_regFLAGS &=
(1 << reg)) ;
return 0 ;
}
/// Возвращает значение указанного флага
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regGet(int8_t reg, bool *value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
*value = sc_regFLAGS & (1 << reg) ;
return 0 ;
}
/// Кодирует команду с указанным номером и операндом и помещает результат в value
/// \param command - команда
/// \param operand - операнд
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandEncode(unsigned short int command, unsigned short int operand, unsigned short int * value){
if (command > 0x7F)
return -1 ;
if (operand > 0x7F)
return -1 ;
* value = 0 ;
/* Операнд */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (operand >> i) & 1 ;
*value |= (bit << i) ;
}
/* Команда */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (command >> i) & 1 ;
*value |= (bit << (i + 7)) ;
}
return 0 ;
}
/// Декодирует значение как команду SС
/// \param value - значение
/// \param command - команда
/// \param operand - операнд
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandDecode(unsigned short int value, unsigned short int * command, unsigned short int * operand){
int tmpCom = 0, tmpOp = 0 ;
if ((value >> 14) & 1){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> i) & 1 ;
tmpOp |= (bit << i) ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> (i + 7)) & 1 ;
tmpCom |= (bit << i) ;
}
* command = tmpCom ;
* operand = tmpOp ;
return 0 ;
}
myTerm.hpp
#ifndef MYTERM_HPP
#define MYTERM_HPP
#include
#include
enum colors {
RED = 196,
PEACH = 203,
GREEN = 10,
SOFT_GREEN =192,
BLUE = 20,
BLACK = 16,
GRAY = 240,
WHITE = 15,
DEFAULT = 0};
int mt_clrScreen () ;
int mt_gotoXY(unsigned int col,unsigned int row) ;
int mt_getScreenSize(unsigned int *rows, unsigned int* cols) ;
int mt_setFGcolor(enum colors color) ;
int mt_setBGcolor(enum colors color) ;
int mt_setDefaultColorSettings() ;
#endif //MYTERM_HPP
myTerm.cpp
#include "myTerm.hpp"
/// Производит очистку и перемещение курсора в левый верхний угол экрана
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_clrScreen (){
printf("\033[H\033[2J") ;
return 0 ;
}
/// Перемещает курсор в указанную позицию
/// \param col - столбец
/// \param row - строка
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_gotoXY(unsigned int col, unsigned int row)
{
unsigned int rows, cols ;
if (mt_getScreenSize(&rows, &cols) == -1)
return -1 ;
if ((row > rows) || (row <= 0)||(col > cols) || (col <= 0))
return -1 ;
printf("\033[%d;%dH", row, col) ;
return 0 ;
}
/// Определяет размер экрана терминала
/// \param rows - кол-во строк
/// \param cols - кол-во столбцов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_getScreenSize(unsigned int *rows, unsigned int *cols){
winsize ws{} ;
if (ioctl(1, TIOCGWINSZ, &ws))
return -1 ;
* rows = ws.ws_row ;
* cols = ws.ws_col ;
return 0 ;
}
/// Устанавливает цвет последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setFGcolor(enum colors color){
printf("\033[38;5;%dm",color) ;
return 0 ;
}
/// Устанавливает цвет фона последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setBGcolor(enum colors color){
printf("\033[48;5;%dm",color) ;
return 0 ;
}
/// Возвращает цвета в стандартное состояние
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setDefaultColorSettings(){
printf("\033[0m") ;
return 0 ;
}
myUI.hpp
#ifndef MYUI_HPP
#define MYUI_HPP
#include
#include "myBigChars.hpp"
#include "myReadkey.hpp"
#include "simpleComputer.hpp"
int ui_initial() ;
int ui_update() ;
int setCurrMemPointer_to_ICounter() ;
int ui_moveCurrMemPointer(keys key) ;
int ui_setMCellValue() ;
int ui_saveMemory() ;
int ui_loadMemory() ;
int ui_setAccumulator() ;
int ui_setICounter() ;
bool checkCorrectInputHEX(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color);
int clearBuffIn() ;
#endif //MYUI_HPP
myUI.cpp
#include "myUI.hpp"
#include "myReadkey.hpp"
int8_t currMemCell = 0 ;
int drawingBoxes() ;
int drawingTexts() ;
int drawingMemory() ;
int drawingAccumulator() ;
int drawingInstructionCounter() ;
int drawingOperation() ;
int drawingFlags() ;
int drawingBigChar() ;
bool checkCorrectInputHEX(const char *buffer) ;
bool checkCorrectInputDEC(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color) ;
/// "Инициализация" интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_initial(){
currMemCell = 0 ;
if (rk_myTermSave())
return -1 ;
sc_memoryInit() ;
sc_accumulator &= (1 << 14) ;
sc_regInit() ;
sc_regSet(IGNORING_TACT_PULSES, true) ;
return 0 ;
}
/// Обновление интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_update(){
mt_clrScreen() ;
if (drawingBoxes())
return -1 ;
if (drawingTexts())
return -1 ;
if (drawingMemory())
return -1 ;
if (drawingAccumulator())
return -1 ;
if (drawingInstructionCounter())
return -1 ;
if (drawingOperation())
return -1 ;
if (drawingFlags())
return -1 ;
if (drawingBigChar())
return -1 ;
mt_gotoXY(1, 23) ;
printf("Input/Output:\n") ;
return 0 ;
}
/// Перемещение выделенной ячейки на значение ICounter
/// \return 0
int setCurrMemPointer_to_ICounter(){
currMemCell = sc_instructionCounter ;
return 0 ;
}
/// Перемещение выделенной ячейки
/// \param key - Клавиша
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_moveCurrMemPointer(keys key){
switch (key) {
case keys::KEY_UP: (currMemCell <= 9) ? (currMemCell = 90 + currMemCell) : (currMemCell -= 10) ; return 0 ;
case keys::KEY_RIGHT: (!((currMemCell + 1) % 10)) ? (currMemCell -= 9) : (currMemCell += 1) ; return 0 ;
case keys::KEY_DOWN: (currMemCell >= 90) ? (currMemCell = currMemCell - 90) : (currMemCell += 10) ; return 0 ;
case keys::KEY_LEFT: (!(currMemCell % 10)) ? (currMemCell += 9) : (currMemCell -= 1) ; return 0 ;
}
return -1 ;
}
int ui_setMCellValue(){
printf("Set the value of the cell under the number \033[38;5;%dm0x%02X\033[0m\n", colors::SOFT_GREEN, currMemCell) ;
printf("Enter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+')
i = 1 ;
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
if (sc_memorySet(currMemCell, res))
return -1 ;
return 0 ;
}
int ui_saveMemory(){
char filename[102] ;
printf("Saving file...\n") ;
printf("Enter the file name to save > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
printf("\033[38;5;%dmThe file name is too long. The length is trimmed to the first 100 characters.\033[0m\n", BLUE) ;
clearBuffIn(); // очистка потока ввода
}
else
filename[strlen(filename) - 1] = '\0' ;
if (sc_memorySave(filename)){
ui_messageOutput((char *)"Failed to save memory", colors::RED) ;
return -1 ;
}
else
ui_messageOutput((char *)"Successful save", colors::GREEN) ;
return 0 ;
}
int ui_loadMemory(){
char filename[102] ;
printf("Loading file...\n") ;
printf("Enter the file name to load > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
ui_messageOutput((char *)"The name of the file to open is too long (up to 100 characters are allowed)", colors::BLUE) ;
clearBuffIn(); // очистка потока ввода
return -1 ;
}
filename[strlen(filename) - 1] = '\0' ;
if (sc_memoryLoad(filename)){
ui_messageOutput((char *)"Failed to load memory", colors::RED) ;
return -1 ;
}
return 0 ;
}
int ui_setAccumulator(){
// может ли в accumulator храниться команда ? (теперь нет)
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"Accumulator\"\033[0m", colors::GREEN) ;
printf("\nEnter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+'){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if(number > 0x3FFF){
ui_messageOutput((char *)"The command value must not exceed 14 bits (0x3FFF)", colors::RED) ;
return -1 ;
}
else
{
number &= 0x3FFF ;
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
else{
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
}
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
sc_accumulator = res ;
return 0 ;
}
int ui_setICounter(){
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"InstructionCounter\"\033[0m between \033[38;5;%dm00\033[0m and \033[38;5;%dm99\033[0m inclusive\n", colors::GREEN, colors::SOFT_GREEN, colors::SOFT_GREEN) ;
printf("Enter value in \033[38;5;%dmDEC\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
if (!checkCorrectInputDEC(buffer)){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(buffer, &tmp, 10);
if(number > 99){
ui_messageOutput((char *)"The value must not exceed the amount of memory", colors::RED) ;
return -1 ;
}
sc_instructionCounter = (uint8_t)number ;
return 0 ;
}
/// Отрисовка "боксов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBoxes(){
if (bc_box(1, 1, 61, 12)) // Окно Memory
return -1 ;
if (bc_box(62, 1, 22, 3)) // Окно accumulator
return -1 ;
if (bc_box(62, 4, 22, 3)) // Окно instructionCounter
return -1 ;
if (bc_box(62, 7, 22, 3)) // Окно Operation
return -1 ;
if (bc_box(62, 10, 22, 3)) // Окно Flags
return -1 ;
if (bc_box(1, 13, 52, 10)) // Окно BigChars
return -1 ;
if (bc_box(53, 13, 31, 10)) // Окно Keys
return -1 ;
return 0 ;
}
/// Отрисовка заголовков и текста
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingTexts(){
/* Заголовки */
mt_gotoXY(30,1) ;
printf(" Memory ") ;
mt_gotoXY(66,1) ;
printf(" accumulator ") ;
mt_gotoXY(63,4) ;
printf(" instructionCounter ") ;
mt_gotoXY(67,7) ;
printf(" Operation ") ;
mt_gotoXY(69,10) ;
printf(" Flags ") ;
mt_gotoXY(54,13) ;
printf(" Keys: ") ;
/* HotKeys */
char* hotK[] = {(char *)"l - load",
(char *)"s - save",
(char *)"r - run",
(char *)"t - step",
(char *)"i - reset",
(char *)"F5 - accumulator",
(char *)"F6 - instructionCounter"};
for (int i = 0 ; i < sizeof(hotK) / sizeof(*hotK) ; ++i) {
mt_gotoXY(54,i + 14) ;
printf("%s", hotK[i]) ;
}
return 0 ;
}
/// Отрисовка памяти
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingMemory(){
for (int i = 0 ; i < 10 ; ++i)
for (int j = 0 ; j < 10 ; ++j) {
mt_gotoXY(2 + (5 * j + j), 2 + i) ;
unsigned short int tmp ;
sc_memoryGet(i * 10 + j, &tmp) ;
if ((i * 10 + j) == currMemCell)
mt_setBGcolor(colors::GREEN) ;
if((tmp >> 14) & 1)
if((tmp >> 13) & 1)
printf("-%04X", (
(tmp - 1)) & 0x3FFF) ;
else
printf(" %04X", tmp & 0x1FFF) ;
else
printf("+%04X", tmp) ;
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка accumulator
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingAccumulator(){
mt_gotoXY(70,2) ;
// bool over ;
// sc_regGet(OVERFLOW, &over) ;
// if (over){
// mt_setFGcolor(colors::PEACH) ;
// printf(" over") ;
// mt_setDefaultColorSettings() ;
// }
// else{
if((sc_accumulator >> 14) & 1)
if((sc_accumulator >> 13) & 1)
printf("-%04X", (
(sc_accumulator - 1)) & 0x3FFF) ;
else
printf(" %04X", sc_accumulator & 0x1FFF) ;
else
printf("+%04X", sc_accumulator) ;
// }
return 0 ;
}
/// Отрисовка Operation
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingOperation(){
mt_gotoXY(69,8) ;
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1)){
unsigned short int operand, command ;
sc_commandDecode(tmp, &command, &operand) ;
printf("+%02X:%02X", command, operand) ;
}
else{
unsigned short int left, right ;
bool negative = (tmp >> 13) & 1 ;
if(negative)
tmp = (
(tmp - 1)) & 0x3FFF ;
Приложение. Листинг
Makefile
d.PHONY: all clean run
COMPILER := g++
FLAGS := -fdiagnostics-color=always -Werror -MMD
SRC_SC := src/sc
BUILD_SC := build/sc
LIBS_SC := libs/sc
SRC_SA := src/sa
BUILD_SA := build/sa
SRC_SB := src/sb
BUILD_SB := build/sb
BIN := bin
SC := simpleComputer
SA := simpleAssembler
SB := simpleBasic
all: create $(BIN)/$(SC) $(BIN)/$(SA) $(BIN)/$(SB)
-include $((BUILD_SC)/*.d
-include $((BUILD_SA)/*.d
-include $((BUILD_SB)/*.d
sc: create $(BIN)/$(SC)
run_sc: sc
./$(BIN)/$(SC)
$(BIN)/$(SC): $(LIBS_SC)/libsimpleComputer.a $(LIBS_SC)/libmyTerm.a $(LIBS_SC)/libmyBigChars.a $(LIBS_SC)/libmyReadkey.a $(LIBS_SC)/libmyUI.a $(LIBS_SC)/libmyALU.a $(LIBS_SC)/libmyCU.a $(BUILD_SC)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SC) $(BUILD_SC)/main.o -L $(LIBS_SC) -lsimpleComputer -lmyUI -lmyTerm -lmyBigChars -lmyReadkey -lmyCU -lmyALU
$(BUILD_SC)/%.o: $(SRC_SC)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
$(LIBS_SC)/libsimpleComputer.a: $(BUILD_SC)/simpleComputer.o
ar cr $@ $^
$(LIBS_SC)/libmyTerm.a: $(BUILD_SC)/myTerm.o
ar cr $@ $^
$(LIBS_SC)/libmyBigChars.a: $(BUILD_SC)/myBigChars.o
ar cr $@ $^
$(LIBS_SC)/libmyReadkey.a: $(BUILD_SC)/myReadkey.o
ar cr $@ $^
$(LIBS_SC)/libmyUI.a: $(BUILD_SC)/myUI.o
ar cr $@ $^
$(LIBS_SC)/libmyALU.a: $(BUILD_SC)/myALU.o
ar cr $@ $^
$(LIBS_SC)/libmyCU.a: $(BUILD_SC)/myCU.o
ar cr $@ $^
sa: create $(BIN)/$(SA)
run_sa: create $(BIN)/$(SA)
./$(BIN)/$(SA)
$(BIN)/$(SA): $(BUILD_SA)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SA) $(BUILD_SA)/main.o
$(BUILD_SA)/%.o: $(SRC_SA)/%.cpps
$(COMPILER) $(FLAGS) -c $^ -o $@
sb: create $(BIN)/$(SB)
run_sb: create $(BIN)/$(SB)
./$(BIN)/$(SB)
$(BIN)/$(SB): $(BUILD_SB)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SB) $(BUILD_SB)/main.o
$(BUILD_SB)/%.o: $(SRC_SB)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
create:
mkdir -p $(BUILD_SC) $(BUILD_SA) $(BUILD_SB) $(LIBS_SC) $(BIN)
clean:
@rm -rf build libs $(BIN)
SimpleComputer
main.cpp
#include
#include "simpleComputer.hpp"
#include "myUI.hpp"
#include "myReadkey.hpp"
#include "myCU.hpp"
void signalHandler(int signal) ;
#include
int main(int argc, char const *argv[]){
ui_initial() ;
signal(SIGALRM, signalHandler) ;
signal(SIGUSR1, signalHandler) ;
bool zero, out, ignor, comm ;
keys key;
if (argc == 2){
sc_memoryLoad((char *)argv[1]) ;
}
else if (argc > 2){
ui_messageOutput((char *)"Exceeded the number of arguments", colors::RED) ;
return -1 ;
}
do {
sc_regGet(IGNORING_TACT_PULSES, &ignor);
ui_update() ;
rk_readKey(&key);
if (ignor){
sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
sc_regGet(OUT_OF_MEMORY, &out) ;
sc_regGet(INCORRECT_COMMAND, &comm) ;
if (zero || out || comm){
switch(key){
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
}
}
else{
switch(key){
case keys::KEY_UP:
ui_moveCurrMemPointer(keys::KEY_UP) ;
break ;
case keys::KEY_RIGHT:
ui_moveCurrMemPointer(keys::KEY_RIGHT) ;
break ;
case keys::KEY_DOWN:
ui_moveCurrMemPointer(keys::KEY_DOWN) ;
break ;
case keys::KEY_LEFT:
ui_moveCurrMemPointer(keys::KEY_LEFT) ;
break ;
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_R:
sc_regInit() ;
raise(SIGALRM) ;
break ;
case keys::KEY_T:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
CU() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
case keys::KEY_F5:
ui_setAccumulator() ;
break ;
case keys::KEY_F6:
ui_setICounter() ;
break ;
case keys::KEY_ENTER:
ui_setMCellValue() ;
break ;
}
}
}
else
if (key == keys::KEY_I)
raise(SIGUSR1) ;
} while(key != keys::KEY_ESC) ;
return 0 ;
}
void signalHandler(int signal){
switch (signal) {
case SIGALRM:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
if (CU()){
sc_regSet(IGNORING_TACT_PULSES, true);
ui_update() ;
alarm(0) ;
}
else
alarm(1) ;
rk_myTermRegime(false, 0, 0, false, false) ;
break ;
case SIGUSR1:
alarm(0) ;
ui_initial() ;
break ;
default:
break ;
}
}
simpleComputer.hpp
#ifndef SIMPLECOMPUTER_HPP
#define SIMPLECOMPUTER_HPP
#include
#define OVERFLOW 0 // Переполнение при выполнении операции
#define DIVISION_ERR_BY_ZERO 1 // Ошибка деления на 0
#define OUT_OF_MEMORY 2 // Ошибка выхода за границы памяти
#define IGNORING_TACT_PULSES 3 // Игнорирование тактовых импульсов
#define INCORRECT_COMMAND 4 // Указана неверная команда
const short int SC_REG_SIZE = 5 ;
const short int SC_MEM_SIZE = 100 ;
extern unsigned short int sc_accumulator ;
extern uint8_t sc_instructionCounter ;
int sc_memoryInit () ;
int sc_memorySet (unsigned short int address, unsigned short int value) ;
int sc_memoryGet (unsigned short int address, unsigned short int * value) ;
int sc_memorySave (char* filename) ;
int sc_memoryLoad (char* filename) ;
int sc_regInit () ;
int sc_regSet (int8_t reg, bool value) ;
int sc_regGet (int8_t reg, bool * value) ;
int sc_commandEncode (unsigned short int command, unsigned short int operand, unsigned short int * value) ;
int sc_commandDecode (unsigned short int value, unsigned short int * command, unsigned short int * operand) ;
#endif //SIMPLECOMPUTER_HPP
simpleComputer.cpp
#include "simpleComputer.hpp"
unsigned short int sc_memory[SC_MEM_SIZE] ;
uint8_t sc_regFLAGS ;
unsigned short int sc_accumulator ;
uint8_t sc_instructionCounter ;
/// Инициализирует оперативную память SC, задавая всем её ячейкам нулевые значения
/// \return 0
int sc_memoryInit()
{
sc_instructionCounter = 0 ;
for (unsigned short & mem : sc_memory)
mem = 0 ;
return 0 ;
}
/// Задает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySet(unsigned short int address, unsigned short int value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_memory[address] = value ;
return 0 ;
}
/// Возвращает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryGet(unsigned short int address, unsigned short int * value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
*value = sc_memory[address] ;
return 0 ;
}
/// Сохраняет содержимое памяти в файл в бинарном виде
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySave(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "wb"))){
return -1 ;
}
fwrite(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Загружает из указанного файла содержимое оперативной памяти
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryLoad(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "rb"))){
return -1 ;
}
fread(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Инициализирует регистр флагов нулевым значением
/// \return 0
int sc_regInit(){
sc_regFLAGS = 0 ;
return 0 ;
}
/// Устанавливает значение указанного регистра флагов
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regSet(int8_t reg, bool value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
value == 1 ? (sc_regFLAGS |= (1 << reg)) : (sc_regFLAGS &=
(1 << reg)) ;
return 0 ;
}
/// Возвращает значение указанного флага
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regGet(int8_t reg, bool *value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
*value = sc_regFLAGS & (1 << reg) ;
return 0 ;
}
/// Кодирует команду с указанным номером и операндом и помещает результат в value
/// \param command - команда
/// \param operand - операнд
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandEncode(unsigned short int command, unsigned short int operand, unsigned short int * value){
if (command > 0x7F)
return -1 ;
if (operand > 0x7F)
return -1 ;
* value = 0 ;
/* Операнд */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (operand >> i) & 1 ;
*value |= (bit << i) ;
}
/* Команда */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (command >> i) & 1 ;
*value |= (bit << (i + 7)) ;
}
return 0 ;
}
/// Декодирует значение как команду SС
/// \param value - значение
/// \param command - команда
/// \param operand - операнд
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandDecode(unsigned short int value, unsigned short int * command, unsigned short int * operand){
int tmpCom = 0, tmpOp = 0 ;
if ((value >> 14) & 1){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> i) & 1 ;
tmpOp |= (bit << i) ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> (i + 7)) & 1 ;
tmpCom |= (bit << i) ;
}
* command = tmpCom ;
* operand = tmpOp ;
return 0 ;
}
myTerm.hpp
#ifndef MYTERM_HPP
#define MYTERM_HPP
#include
#include
enum colors {
RED = 196,
PEACH = 203,
GREEN = 10,
SOFT_GREEN =192,
BLUE = 20,
BLACK = 16,
GRAY = 240,
WHITE = 15,
DEFAULT = 0};
int mt_clrScreen () ;
int mt_gotoXY(unsigned int col,unsigned int row) ;
int mt_getScreenSize(unsigned int *rows, unsigned int* cols) ;
int mt_setFGcolor(enum colors color) ;
int mt_setBGcolor(enum colors color) ;
int mt_setDefaultColorSettings() ;
#endif //MYTERM_HPP
myTerm.cpp
#include "myTerm.hpp"
/// Производит очистку и перемещение курсора в левый верхний угол экрана
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_clrScreen (){
printf("\033[H\033[2J") ;
return 0 ;
}
/// Перемещает курсор в указанную позицию
/// \param col - столбец
/// \param row - строка
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_gotoXY(unsigned int col, unsigned int row)
{
unsigned int rows, cols ;
if (mt_getScreenSize(&rows, &cols) == -1)
return -1 ;
if ((row > rows) || (row <= 0)||(col > cols) || (col <= 0))
return -1 ;
printf("\033[%d;%dH", row, col) ;
return 0 ;
}
/// Определяет размер экрана терминала
/// \param rows - кол-во строк
/// \param cols - кол-во столбцов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_getScreenSize(unsigned int *rows, unsigned int *cols){
winsize ws{} ;
if (ioctl(1, TIOCGWINSZ, &ws))
return -1 ;
* rows = ws.ws_row ;
* cols = ws.ws_col ;
return 0 ;
}
/// Устанавливает цвет последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setFGcolor(enum colors color){
printf("\033[38;5;%dm",color) ;
return 0 ;
}
/// Устанавливает цвет фона последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setBGcolor(enum colors color){
printf("\033[48;5;%dm",color) ;
return 0 ;
}
/// Возвращает цвета в стандартное состояние
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setDefaultColorSettings(){
printf("\033[0m") ;
return 0 ;
}
myUI.hpp
#ifndef MYUI_HPP
#define MYUI_HPP
#include
#include "myBigChars.hpp"
#include "myReadkey.hpp"
#include "simpleComputer.hpp"
int ui_initial() ;
int ui_update() ;
int setCurrMemPointer_to_ICounter() ;
int ui_moveCurrMemPointer(keys key) ;
int ui_setMCellValue() ;
int ui_saveMemory() ;
int ui_loadMemory() ;
int ui_setAccumulator() ;
int ui_setICounter() ;
bool checkCorrectInputHEX(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color);
int clearBuffIn() ;
#endif //MYUI_HPP
myUI.cpp
#include "myUI.hpp"
#include "myReadkey.hpp"
int8_t currMemCell = 0 ;
int drawingBoxes() ;
int drawingTexts() ;
int drawingMemory() ;
int drawingAccumulator() ;
int drawingInstructionCounter() ;
int drawingOperation() ;
int drawingFlags() ;
int drawingBigChar() ;
bool checkCorrectInputHEX(const char *buffer) ;
bool checkCorrectInputDEC(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color) ;
/// "Инициализация" интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_initial(){
currMemCell = 0 ;
if (rk_myTermSave())
return -1 ;
sc_memoryInit() ;
sc_accumulator &= (1 << 14) ;
sc_regInit() ;
sc_regSet(IGNORING_TACT_PULSES, true) ;
return 0 ;
}
/// Обновление интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_update(){
mt_clrScreen() ;
if (drawingBoxes())
return -1 ;
if (drawingTexts())
return -1 ;
if (drawingMemory())
return -1 ;
if (drawingAccumulator())
return -1 ;
if (drawingInstructionCounter())
return -1 ;
if (drawingOperation())
return -1 ;
if (drawingFlags())
return -1 ;
if (drawingBigChar())
return -1 ;
mt_gotoXY(1, 23) ;
printf("Input/Output:\n") ;
return 0 ;
}
/// Перемещение выделенной ячейки на значение ICounter
/// \return 0
int setCurrMemPointer_to_ICounter(){
currMemCell = sc_instructionCounter ;
return 0 ;
}
/// Перемещение выделенной ячейки
/// \param key - Клавиша
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_moveCurrMemPointer(keys key){
switch (key) {
case keys::KEY_UP: (currMemCell <= 9) ? (currMemCell = 90 + currMemCell) : (currMemCell -= 10) ; return 0 ;
case keys::KEY_RIGHT: (!((currMemCell + 1) % 10)) ? (currMemCell -= 9) : (currMemCell += 1) ; return 0 ;
case keys::KEY_DOWN: (currMemCell >= 90) ? (currMemCell = currMemCell - 90) : (currMemCell += 10) ; return 0 ;
case keys::KEY_LEFT: (!(currMemCell % 10)) ? (currMemCell += 9) : (currMemCell -= 1) ; return 0 ;
}
return -1 ;
}
int ui_setMCellValue(){
printf("Set the value of the cell under the number \033[38;5;%dm0x%02X\033[0m\n", colors::SOFT_GREEN, currMemCell) ;
printf("Enter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+')
i = 1 ;
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
if (sc_memorySet(currMemCell, res))
return -1 ;
return 0 ;
}
int ui_saveMemory(){
char filename[102] ;
printf("Saving file...\n") ;
printf("Enter the file name to save > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
printf("\033[38;5;%dmThe file name is too long. The length is trimmed to the first 100 characters.\033[0m\n", BLUE) ;
clearBuffIn(); // очистка потока ввода
}
else
filename[strlen(filename) - 1] = '\0' ;
if (sc_memorySave(filename)){
ui_messageOutput((char *)"Failed to save memory", colors::RED) ;
return -1 ;
}
else
ui_messageOutput((char *)"Successful save", colors::GREEN) ;
return 0 ;
}
int ui_loadMemory(){
char filename[102] ;
printf("Loading file...\n") ;
printf("Enter the file name to load > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
ui_messageOutput((char *)"The name of the file to open is too long (up to 100 characters are allowed)", colors::BLUE) ;
clearBuffIn(); // очистка потока ввода
return -1 ;
}
filename[strlen(filename) - 1] = '\0' ;
if (sc_memoryLoad(filename)){
ui_messageOutput((char *)"Failed to load memory", colors::RED) ;
return -1 ;
}
return 0 ;
}
int ui_setAccumulator(){
// может ли в accumulator храниться команда ? (теперь нет)
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"Accumulator\"\033[0m", colors::GREEN) ;
printf("\nEnter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+'){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if(number > 0x3FFF){
ui_messageOutput((char *)"The command value must not exceed 14 bits (0x3FFF)", colors::RED) ;
return -1 ;
}
else
{
number &= 0x3FFF ;
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
else{
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
}
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
sc_accumulator = res ;
return 0 ;
}
int ui_setICounter(){
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"InstructionCounter\"\033[0m between \033[38;5;%dm00\033[0m and \033[38;5;%dm99\033[0m inclusive\n", colors::GREEN, colors::SOFT_GREEN, colors::SOFT_GREEN) ;
printf("Enter value in \033[38;5;%dmDEC\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
if (!checkCorrectInputDEC(buffer)){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(buffer, &tmp, 10);
if(number > 99){
ui_messageOutput((char *)"The value must not exceed the amount of memory", colors::RED) ;
return -1 ;
}
sc_instructionCounter = (uint8_t)number ;
return 0 ;
}
/// Отрисовка "боксов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBoxes(){
if (bc_box(1, 1, 61, 12)) // Окно Memory
return -1 ;
if (bc_box(62, 1, 22, 3)) // Окно accumulator
return -1 ;
if (bc_box(62, 4, 22, 3)) // Окно instructionCounter
return -1 ;
if (bc_box(62, 7, 22, 3)) // Окно Operation
return -1 ;
if (bc_box(62, 10, 22, 3)) // Окно Flags
return -1 ;
if (bc_box(1, 13, 52, 10)) // Окно BigChars
return -1 ;
if (bc_box(53, 13, 31, 10)) // Окно Keys
return -1 ;
return 0 ;
}
/// Отрисовка заголовков и текста
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingTexts(){
/* Заголовки */
mt_gotoXY(30,1) ;
printf(" Memory ") ;
mt_gotoXY(66,1) ;
printf(" accumulator ") ;
mt_gotoXY(63,4) ;
printf(" instructionCounter ") ;
mt_gotoXY(67,7) ;
printf(" Operation ") ;
mt_gotoXY(69,10) ;
printf(" Flags ") ;
mt_gotoXY(54,13) ;
printf(" Keys: ") ;
/* HotKeys */
char* hotK[] = {(char *)"l - load",
(char *)"s - save",
(char *)"r - run",
(char *)"t - step",
(char *)"i - reset",
(char *)"F5 - accumulator",
(char *)"F6 - instructionCounter"};
for (int i = 0 ; i < sizeof(hotK) / sizeof(*hotK) ; ++i) {
mt_gotoXY(54,i + 14) ;
printf("%s", hotK[i]) ;
}
return 0 ;
}
/// Отрисовка памяти
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingMemory(){
for (int i = 0 ; i < 10 ; ++i)
for (int j = 0 ; j < 10 ; ++j) {
mt_gotoXY(2 + (5 * j + j), 2 + i) ;
unsigned short int tmp ;
sc_memoryGet(i * 10 + j, &tmp) ;
if ((i * 10 + j) == currMemCell)
mt_setBGcolor(colors::GREEN) ;
if((tmp >> 14) & 1)
if((tmp >> 13) & 1)
printf("-%04X", (
(tmp - 1)) & 0x3FFF) ;
Приложение. Листинг
Makefile
d.PHONY: all clean run
COMPILER := g++
FLAGS := -fdiagnostics-color=always -Werror -MMD
SRC_SC := src/sc
BUILD_SC := build/sc
LIBS_SC := libs/sc
SRC_SA := src/sa
BUILD_SA := build/sa
SRC_SB := src/sb
BUILD_SB := build/sb
BIN := bin
SC := simpleComputer
SA := simpleAssembler
SB := simpleBasic
all: create $(BIN)/$(SC) $(BIN)/$(SA) $(BIN)/$(SB)
-include $((BUILD_SC)/*.d
-include $((BUILD_SA)/*.d
-include $((BUILD_SB)/*.d
sc: create $(BIN)/$(SC)
run_sc: sc
./$(BIN)/$(SC)
$(BIN)/$(SC): $(LIBS_SC)/libsimpleComputer.a $(LIBS_SC)/libmyTerm.a $(LIBS_SC)/libmyBigChars.a $(LIBS_SC)/libmyReadkey.a $(LIBS_SC)/libmyUI.a $(LIBS_SC)/libmyALU.a $(LIBS_SC)/libmyCU.a $(BUILD_SC)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SC) $(BUILD_SC)/main.o -L $(LIBS_SC) -lsimpleComputer -lmyUI -lmyTerm -lmyBigChars -lmyReadkey -lmyCU -lmyALU
$(BUILD_SC)/%.o: $(SRC_SC)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
$(LIBS_SC)/libsimpleComputer.a: $(BUILD_SC)/simpleComputer.o
ar cr $@ $^
$(LIBS_SC)/libmyTerm.a: $(BUILD_SC)/myTerm.o
ar cr $@ $^
$(LIBS_SC)/libmyBigChars.a: $(BUILD_SC)/myBigChars.o
ar cr $@ $^
$(LIBS_SC)/libmyReadkey.a: $(BUILD_SC)/myReadkey.o
ar cr $@ $^
$(LIBS_SC)/libmyUI.a: $(BUILD_SC)/myUI.o
ar cr $@ $^
$(LIBS_SC)/libmyALU.a: $(BUILD_SC)/myALU.o
ar cr $@ $^
$(LIBS_SC)/libmyCU.a: $(BUILD_SC)/myCU.o
ar cr $@ $^
sa: create $(BIN)/$(SA)
run_sa: create $(BIN)/$(SA)
./$(BIN)/$(SA)
$(BIN)/$(SA): $(BUILD_SA)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SA) $(BUILD_SA)/main.o
$(BUILD_SA)/%.o: $(SRC_SA)/%.cpps
$(COMPILER) $(FLAGS) -c $^ -o $@
sb: create $(BIN)/$(SB)
run_sb: create $(BIN)/$(SB)
./$(BIN)/$(SB)
$(BIN)/$(SB): $(BUILD_SB)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SB) $(BUILD_SB)/main.o
$(BUILD_SB)/%.o: $(SRC_SB)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
create:
mkdir -p $(BUILD_SC) $(BUILD_SA) $(BUILD_SB) $(LIBS_SC) $(BIN)
clean:
@rm -rf build libs $(BIN)
SimpleComputer
main.cpp
#include
#include "simpleComputer.hpp"
#include "myUI.hpp"
#include "myReadkey.hpp"
#include "myCU.hpp"
void signalHandler(int signal) ;
#include
int main(int argc, char const *argv[]){
ui_initial() ;
signal(SIGALRM, signalHandler) ;
signal(SIGUSR1, signalHandler) ;
bool zero, out, ignor, comm ;
keys key;
if (argc == 2){
sc_memoryLoad((char *)argv[1]) ;
}
else if (argc > 2){
ui_messageOutput((char *)"Exceeded the number of arguments", colors::RED) ;
return -1 ;
}
do {
sc_regGet(IGNORING_TACT_PULSES, &ignor);
ui_update() ;
rk_readKey(&key);
if (ignor){
sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
sc_regGet(OUT_OF_MEMORY, &out) ;
sc_regGet(INCORRECT_COMMAND, &comm) ;
if (zero || out || comm){
switch(key){
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
}
}
else{
switch(key){
case keys::KEY_UP:
ui_moveCurrMemPointer(keys::KEY_UP) ;
break ;
case keys::KEY_RIGHT:
ui_moveCurrMemPointer(keys::KEY_RIGHT) ;
break ;
case keys::KEY_DOWN:
ui_moveCurrMemPointer(keys::KEY_DOWN) ;
break ;
case keys::KEY_LEFT:
ui_moveCurrMemPointer(keys::KEY_LEFT) ;
break ;
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_R:
sc_regInit() ;
raise(SIGALRM) ;
break ;
case keys::KEY_T:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
CU() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
case keys::KEY_F5:
ui_setAccumulator() ;
break ;
case keys::KEY_F6:
ui_setICounter() ;
break ;
case keys::KEY_ENTER:
ui_setMCellValue() ;
break ;
}
}
}
else
if (key == keys::KEY_I)
raise(SIGUSR1) ;
} while(key != keys::KEY_ESC) ;
return 0 ;
}
void signalHandler(int signal){
switch (signal) {
case SIGALRM:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
if (CU()){
sc_regSet(IGNORING_TACT_PULSES, true);
ui_update() ;
alarm(0) ;
}
else
alarm(1) ;
rk_myTermRegime(false, 0, 0, false, false) ;
break ;
case SIGUSR1:
alarm(0) ;
ui_initial() ;
break ;
default:
break ;
}
}
simpleComputer.hpp
#ifndef SIMPLECOMPUTER_HPP
#define SIMPLECOMPUTER_HPP
#include
#define OVERFLOW 0 // Переполнение при выполнении операции
#define DIVISION_ERR_BY_ZERO 1 // Ошибка деления на 0
#define OUT_OF_MEMORY 2 // Ошибка выхода за границы памяти
#define IGNORING_TACT_PULSES 3 // Игнорирование тактовых импульсов
#define INCORRECT_COMMAND 4 // Указана неверная команда
const short int SC_REG_SIZE = 5 ;
const short int SC_MEM_SIZE = 100 ;
extern unsigned short int sc_accumulator ;
extern uint8_t sc_instructionCounter ;
int sc_memoryInit () ;
int sc_memorySet (unsigned short int address, unsigned short int value) ;
int sc_memoryGet (unsigned short int address, unsigned short int * value) ;
int sc_memorySave (char* filename) ;
int sc_memoryLoad (char* filename) ;
int sc_regInit () ;
int sc_regSet (int8_t reg, bool value) ;
int sc_regGet (int8_t reg, bool * value) ;
int sc_commandEncode (unsigned short int command, unsigned short int operand, unsigned short int * value) ;
int sc_commandDecode (unsigned short int value, unsigned short int * command, unsigned short int * operand) ;
#endif //SIMPLECOMPUTER_HPP
simpleComputer.cpp
#include "simpleComputer.hpp"
unsigned short int sc_memory[SC_MEM_SIZE] ;
uint8_t sc_regFLAGS ;
unsigned short int sc_accumulator ;
uint8_t sc_instructionCounter ;
/// Инициализирует оперативную память SC, задавая всем её ячейкам нулевые значения
/// \return 0
int sc_memoryInit()
{
sc_instructionCounter = 0 ;
for (unsigned short & mem : sc_memory)
mem = 0 ;
return 0 ;
}
/// Задает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySet(unsigned short int address, unsigned short int value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_memory[address] = value ;
return 0 ;
}
/// Возвращает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryGet(unsigned short int address, unsigned short int * value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
*value = sc_memory[address] ;
return 0 ;
}
/// Сохраняет содержимое памяти в файл в бинарном виде
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySave(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "wb"))){
return -1 ;
}
fwrite(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Загружает из указанного файла содержимое оперативной памяти
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryLoad(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "rb"))){
return -1 ;
}
fread(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Инициализирует регистр флагов нулевым значением
/// \return 0
int sc_regInit(){
sc_regFLAGS = 0 ;
return 0 ;
}
/// Устанавливает значение указанного регистра флагов
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regSet(int8_t reg, bool value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
value == 1 ? (sc_regFLAGS |= (1 << reg)) : (sc_regFLAGS &=
(1 << reg)) ;
return 0 ;
}
/// Возвращает значение указанного флага
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regGet(int8_t reg, bool *value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
*value = sc_regFLAGS & (1 << reg) ;
return 0 ;
}
/// Кодирует команду с указанным номером и операндом и помещает результат в value
/// \param command - команда
/// \param operand - операнд
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandEncode(unsigned short int command, unsigned short int operand, unsigned short int * value){
if (command > 0x7F)
return -1 ;
if (operand > 0x7F)
return -1 ;
* value = 0 ;
/* Операнд */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (operand >> i) & 1 ;
*value |= (bit << i) ;
}
/* Команда */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (command >> i) & 1 ;
*value |= (bit << (i + 7)) ;
}
return 0 ;
}
/// Декодирует значение как команду SС
/// \param value - значение
/// \param command - команда
/// \param operand - операнд
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandDecode(unsigned short int value, unsigned short int * command, unsigned short int * operand){
int tmpCom = 0, tmpOp = 0 ;
if ((value >> 14) & 1){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> i) & 1 ;
tmpOp |= (bit << i) ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> (i + 7)) & 1 ;
tmpCom |= (bit << i) ;
}
* command = tmpCom ;
* operand = tmpOp ;
return 0 ;
}
myTerm.hpp
#ifndef MYTERM_HPP
#define MYTERM_HPP
#include
#include
enum colors {
RED = 196,
PEACH = 203,
GREEN = 10,
SOFT_GREEN =192,
BLUE = 20,
BLACK = 16,
GRAY = 240,
WHITE = 15,
DEFAULT = 0};
int mt_clrScreen () ;
int mt_gotoXY(unsigned int col,unsigned int row) ;
int mt_getScreenSize(unsigned int *rows, unsigned int* cols) ;
int mt_setFGcolor(enum colors color) ;
int mt_setBGcolor(enum colors color) ;
int mt_setDefaultColorSettings() ;
#endif //MYTERM_HPP
myTerm.cpp
#include "myTerm.hpp"
/// Производит очистку и перемещение курсора в левый верхний угол экрана
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_clrScreen (){
printf("\033[H\033[2J") ;
return 0 ;
}
/// Перемещает курсор в указанную позицию
/// \param col - столбец
/// \param row - строка
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_gotoXY(unsigned int col, unsigned int row)
{
unsigned int rows, cols ;
if (mt_getScreenSize(&rows, &cols) == -1)
return -1 ;
if ((row > rows) || (row <= 0)||(col > cols) || (col <= 0))
return -1 ;
printf("\033[%d;%dH", row, col) ;
return 0 ;
}
/// Определяет размер экрана терминала
/// \param rows - кол-во строк
/// \param cols - кол-во столбцов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_getScreenSize(unsigned int *rows, unsigned int *cols){
winsize ws{} ;
if (ioctl(1, TIOCGWINSZ, &ws))
return -1 ;
* rows = ws.ws_row ;
* cols = ws.ws_col ;
return 0 ;
}
/// Устанавливает цвет последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setFGcolor(enum colors color){
printf("\033[38;5;%dm",color) ;
return 0 ;
}
/// Устанавливает цвет фона последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setBGcolor(enum colors color){
printf("\033[48;5;%dm",color) ;
return 0 ;
}
/// Возвращает цвета в стандартное состояние
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setDefaultColorSettings(){
printf("\033[0m") ;
return 0 ;
}
myUI.hpp
#ifndef MYUI_HPP
#define MYUI_HPP
#include
#include "myBigChars.hpp"
#include "myReadkey.hpp"
#include "simpleComputer.hpp"
int ui_initial() ;
int ui_update() ;
int setCurrMemPointer_to_ICounter() ;
int ui_moveCurrMemPointer(keys key) ;
int ui_setMCellValue() ;
int ui_saveMemory() ;
int ui_loadMemory() ;
int ui_setAccumulator() ;
int ui_setICounter() ;
bool checkCorrectInputHEX(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color);
int clearBuffIn() ;
#endif //MYUI_HPP
myUI.cpp
#include "myUI.hpp"
#include "myReadkey.hpp"
int8_t currMemCell = 0 ;
int drawingBoxes() ;
int drawingTexts() ;
int drawingMemory() ;
int drawingAccumulator() ;
int drawingInstructionCounter() ;
int drawingOperation() ;
int drawingFlags() ;
int drawingBigChar() ;
bool checkCorrectInputHEX(const char *buffer) ;
bool checkCorrectInputDEC(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color) ;
/// "Инициализация" интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_initial(){
currMemCell = 0 ;
if (rk_myTermSave())
return -1 ;
sc_memoryInit() ;
sc_accumulator &= (1 << 14) ;
sc_regInit() ;
sc_regSet(IGNORING_TACT_PULSES, true) ;
return 0 ;
}
/// Обновление интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_update(){
mt_clrScreen() ;
if (drawingBoxes())
return -1 ;
if (drawingTexts())
return -1 ;
if (drawingMemory())
return -1 ;
if (drawingAccumulator())
return -1 ;
if (drawingInstructionCounter())
return -1 ;
if (drawingOperation())
return -1 ;
if (drawingFlags())
return -1 ;
if (drawingBigChar())
return -1 ;
mt_gotoXY(1, 23) ;
printf("Input/Output:\n") ;
return 0 ;
}
/// Перемещение выделенной ячейки на значение ICounter
/// \return 0
int setCurrMemPointer_to_ICounter(){
currMemCell = sc_instructionCounter ;
return 0 ;
}
/// Перемещение выделенной ячейки
/// \param key - Клавиша
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_moveCurrMemPointer(keys key){
switch (key) {
case keys::KEY_UP: (currMemCell <= 9) ? (currMemCell = 90 + currMemCell) : (currMemCell -= 10) ; return 0 ;
case keys::KEY_RIGHT: (!((currMemCell + 1) % 10)) ? (currMemCell -= 9) : (currMemCell += 1) ; return 0 ;
case keys::KEY_DOWN: (currMemCell >= 90) ? (currMemCell = currMemCell - 90) : (currMemCell += 10) ; return 0 ;
case keys::KEY_LEFT: (!(currMemCell % 10)) ? (currMemCell += 9) : (currMemCell -= 1) ; return 0 ;
}
return -1 ;
}
int ui_setMCellValue(){
printf("Set the value of the cell under the number \033[38;5;%dm0x%02X\033[0m\n", colors::SOFT_GREEN, currMemCell) ;
printf("Enter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+')
i = 1 ;
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
if (!((number >> 13) & 1))
res &=
(1 << 13) ;
}
number &= 0x1FFF ;
res |= number ;
}
if (sc_memorySet(currMemCell, res))
return -1 ;
return 0 ;
}
int ui_saveMemory(){
char filename[102] ;
printf("Saving file...\n") ;
printf("Enter the file name to save > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
printf("\033[38;5;%dmThe file name is too long. The length is trimmed to the first 100 characters.\033[0m\n", BLUE) ;
clearBuffIn(); // очистка потока ввода
}
else
filename[strlen(filename) - 1] = '\0' ;
if (sc_memorySave(filename)){
ui_messageOutput((char *)"Failed to save memory", colors::RED) ;
return -1 ;
}
else
ui_messageOutput((char *)"Successful save", colors::GREEN) ;
return 0 ;
}
int ui_loadMemory(){
char filename[102] ;
printf("Loading file...\n") ;
printf("Enter the file name to load > ");
mt_setFGcolor(colors::SOFT_GREEN) ;
fgets(filename, 102, stdin) ;
mt_setDefaultColorSettings() ;
if (filename[strlen(filename) - 1] != '\n'){
ui_messageOutput((char *)"The name of the file to open is too long (up to 100 characters are allowed)", colors::BLUE) ;
clearBuffIn(); // очистка потока ввода
return -1 ;
}
filename[strlen(filename) - 1] = '\0' ;
if (sc_memoryLoad(filename)){
ui_messageOutput((char *)"Failed to load memory", colors::RED) ;
return -1 ;
}
return 0 ;
}
int ui_setAccumulator(){
// может ли в accumulator храниться команда ? (теперь нет)
char buffer[10] ;
printf("Set a value \033[38;5;%dm\"Accumulator\"\033[0m", colors::GREEN) ;
printf("\nEnter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+'){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if(number > 0x3FFF){
ui_messageOutput((char *)"The command value must not exceed 14 bits (0x3FFF)", colors::RED) ;
return -1 ;
}
else
{
number &= 0x3FFF ;
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
else{
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
}
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;
Приложение. Листинг
Makefile
d.PHONY: all clean run
COMPILER := g++
FLAGS := -fdiagnostics-color=always -Werror -MMD
SRC_SC := src/sc
BUILD_SC := build/sc
LIBS_SC := libs/sc
SRC_SA := src/sa
BUILD_SA := build/sa
SRC_SB := src/sb
BUILD_SB := build/sb
BIN := bin
SC := simpleComputer
SA := simpleAssembler
SB := simpleBasic
all: create $(BIN)/$(SC) $(BIN)/$(SA) $(BIN)/$(SB)
-include $((BUILD_SC)/*.d
-include $((BUILD_SA)/*.d
-include $((BUILD_SB)/*.d
sc: create $(BIN)/$(SC)
run_sc: sc
./$(BIN)/$(SC)
$(BIN)/$(SC): $(LIBS_SC)/libsimpleComputer.a $(LIBS_SC)/libmyTerm.a $(LIBS_SC)/libmyBigChars.a $(LIBS_SC)/libmyReadkey.a $(LIBS_SC)/libmyUI.a $(LIBS_SC)/libmyALU.a $(LIBS_SC)/libmyCU.a $(BUILD_SC)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SC) $(BUILD_SC)/main.o -L $(LIBS_SC) -lsimpleComputer -lmyUI -lmyTerm -lmyBigChars -lmyReadkey -lmyCU -lmyALU
$(BUILD_SC)/%.o: $(SRC_SC)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
$(LIBS_SC)/libsimpleComputer.a: $(BUILD_SC)/simpleComputer.o
ar cr $@ $^
$(LIBS_SC)/libmyTerm.a: $(BUILD_SC)/myTerm.o
ar cr $@ $^
$(LIBS_SC)/libmyBigChars.a: $(BUILD_SC)/myBigChars.o
ar cr $@ $^
$(LIBS_SC)/libmyReadkey.a: $(BUILD_SC)/myReadkey.o
ar cr $@ $^
$(LIBS_SC)/libmyUI.a: $(BUILD_SC)/myUI.o
ar cr $@ $^
$(LIBS_SC)/libmyALU.a: $(BUILD_SC)/myALU.o
ar cr $@ $^
$(LIBS_SC)/libmyCU.a: $(BUILD_SC)/myCU.o
ar cr $@ $^
sa: create $(BIN)/$(SA)
run_sa: create $(BIN)/$(SA)
./$(BIN)/$(SA)
$(BIN)/$(SA): $(BUILD_SA)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SA) $(BUILD_SA)/main.o
$(BUILD_SA)/%.o: $(SRC_SA)/%.cpps
$(COMPILER) $(FLAGS) -c $^ -o $@
sb: create $(BIN)/$(SB)
run_sb: create $(BIN)/$(SB)
./$(BIN)/$(SB)
$(BIN)/$(SB): $(BUILD_SB)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SB) $(BUILD_SB)/main.o
$(BUILD_SB)/%.o: $(SRC_SB)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
create:
mkdir -p $(BUILD_SC) $(BUILD_SA) $(BUILD_SB) $(LIBS_SC) $(BIN)
clean:
@rm -rf build libs $(BIN)
SimpleComputer
main.cpp
#include
#include "simpleComputer.hpp"
#include "myUI.hpp"
#include "myReadkey.hpp"
#include "myCU.hpp"
void signalHandler(int signal) ;
#include
int main(int argc, char const *argv[]){
ui_initial() ;
signal(SIGALRM, signalHandler) ;
signal(SIGUSR1, signalHandler) ;
bool zero, out, ignor, comm ;
keys key;
if (argc == 2){
sc_memoryLoad((char *)argv[1]) ;
}
else if (argc > 2){
ui_messageOutput((char *)"Exceeded the number of arguments", colors::RED) ;
return -1 ;
}
do {
sc_regGet(IGNORING_TACT_PULSES, &ignor);
ui_update() ;
rk_readKey(&key);
if (ignor){
sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
sc_regGet(OUT_OF_MEMORY, &out) ;
sc_regGet(INCORRECT_COMMAND, &comm) ;
if (zero || out || comm){
switch(key){
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
}
}
else{
switch(key){
case keys::KEY_UP:
ui_moveCurrMemPointer(keys::KEY_UP) ;
break ;
case keys::KEY_RIGHT:
ui_moveCurrMemPointer(keys::KEY_RIGHT) ;
break ;
case keys::KEY_DOWN:
ui_moveCurrMemPointer(keys::KEY_DOWN) ;
break ;
case keys::KEY_LEFT:
ui_moveCurrMemPointer(keys::KEY_LEFT) ;
break ;
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_R:
sc_regInit() ;
raise(SIGALRM) ;
break ;
case keys::KEY_T:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
CU() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
case keys::KEY_F5:
ui_setAccumulator() ;
break ;
case keys::KEY_F6:
ui_setICounter() ;
break ;
case keys::KEY_ENTER:
ui_setMCellValue() ;
break ;
}
}
}
else
if (key == keys::KEY_I)
raise(SIGUSR1) ;
} while(key != keys::KEY_ESC) ;
return 0 ;
}
void signalHandler(int signal){
switch (signal) {
case SIGALRM:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
if (CU()){
sc_regSet(IGNORING_TACT_PULSES, true);
ui_update() ;
alarm(0) ;
}
else
alarm(1) ;
rk_myTermRegime(false, 0, 0, false, false) ;
break ;
case SIGUSR1:
alarm(0) ;
ui_initial() ;
break ;
default:
break ;
}
}
simpleComputer.hpp
#ifndef SIMPLECOMPUTER_HPP
#define SIMPLECOMPUTER_HPP
#include
#define OVERFLOW 0 // Переполнение при выполнении операции
#define DIVISION_ERR_BY_ZERO 1 // Ошибка деления на 0
#define OUT_OF_MEMORY 2 // Ошибка выхода за границы памяти
#define IGNORING_TACT_PULSES 3 // Игнорирование тактовых импульсов
#define INCORRECT_COMMAND 4 // Указана неверная команда
const short int SC_REG_SIZE = 5 ;
const short int SC_MEM_SIZE = 100 ;
extern unsigned short int sc_accumulator ;
extern uint8_t sc_instructionCounter ;
int sc_memoryInit () ;
int sc_memorySet (unsigned short int address, unsigned short int value) ;
int sc_memoryGet (unsigned short int address, unsigned short int * value) ;
int sc_memorySave (char* filename) ;
int sc_memoryLoad (char* filename) ;
int sc_regInit () ;
int sc_regSet (int8_t reg, bool value) ;
int sc_regGet (int8_t reg, bool * value) ;
int sc_commandEncode (unsigned short int command, unsigned short int operand, unsigned short int * value) ;
int sc_commandDecode (unsigned short int value, unsigned short int * command, unsigned short int * operand) ;
#endif //SIMPLECOMPUTER_HPP
simpleComputer.cpp
#include "simpleComputer.hpp"
unsigned short int sc_memory[SC_MEM_SIZE] ;
uint8_t sc_regFLAGS ;
unsigned short int sc_accumulator ;
uint8_t sc_instructionCounter ;
/// Инициализирует оперативную память SC, задавая всем её ячейкам нулевые значения
/// \return 0
int sc_memoryInit()
{
sc_instructionCounter = 0 ;
for (unsigned short & mem : sc_memory)
mem = 0 ;
return 0 ;
}
/// Задает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySet(unsigned short int address, unsigned short int value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_memory[address] = value ;
return 0 ;
}
/// Возвращает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryGet(unsigned short int address, unsigned short int * value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
*value = sc_memory[address] ;
return 0 ;
}
/// Сохраняет содержимое памяти в файл в бинарном виде
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySave(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "wb"))){
return -1 ;
}
fwrite(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Загружает из указанного файла содержимое оперативной памяти
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryLoad(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "rb"))){
return -1 ;
}
fread(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Инициализирует регистр флагов нулевым значением
/// \return 0
int sc_regInit(){
sc_regFLAGS = 0 ;
return 0 ;
}
/// Устанавливает значение указанного регистра флагов
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regSet(int8_t reg, bool value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
value == 1 ? (sc_regFLAGS |= (1 << reg)) : (sc_regFLAGS &=
(1 << reg)) ;
return 0 ;
}
/// Возвращает значение указанного флага
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regGet(int8_t reg, bool *value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
*value = sc_regFLAGS & (1 << reg) ;
return 0 ;
}
/// Кодирует команду с указанным номером и операндом и помещает результат в value
/// \param command - команда
/// \param operand - операнд
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandEncode(unsigned short int command, unsigned short int operand, unsigned short int * value){
if (command > 0x7F)
return -1 ;
if (operand > 0x7F)
return -1 ;
* value = 0 ;
/* Операнд */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (operand >> i) & 1 ;
*value |= (bit << i) ;
}
/* Команда */
for (int i = 0 ; i < 7 ; i++) {
int8_t bit = (command >> i) & 1 ;
*value |= (bit << (i + 7)) ;
}
return 0 ;
}
/// Декодирует значение как команду SС
/// \param value - значение
/// \param command - команда
/// \param operand - операнд
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_commandDecode(unsigned short int value, unsigned short int * command, unsigned short int * operand){
int tmpCom = 0, tmpOp = 0 ;
if ((value >> 14) & 1){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> i) & 1 ;
tmpOp |= (bit << i) ;
}
for (int i = 0 ; i < 7 ; i++) {
int bit = (value >> (i + 7)) & 1 ;
tmpCom |= (bit << i) ;
}
* command = tmpCom ;
* operand = tmpOp ;
return 0 ;
}
myTerm.hpp
#ifndef MYTERM_HPP
#define MYTERM_HPP
#include
#include
enum colors {
RED = 196,
PEACH = 203,
GREEN = 10,
SOFT_GREEN =192,
BLUE = 20,
BLACK = 16,
GRAY = 240,
WHITE = 15,
DEFAULT = 0};
int mt_clrScreen () ;
int mt_gotoXY(unsigned int col,unsigned int row) ;
int mt_getScreenSize(unsigned int *rows, unsigned int* cols) ;
int mt_setFGcolor(enum colors color) ;
int mt_setBGcolor(enum colors color) ;
int mt_setDefaultColorSettings() ;
#endif //MYTERM_HPP
myTerm.cpp
#include "myTerm.hpp"
/// Производит очистку и перемещение курсора в левый верхний угол экрана
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_clrScreen (){
printf("\033[H\033[2J") ;
return 0 ;
}
/// Перемещает курсор в указанную позицию
/// \param col - столбец
/// \param row - строка
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_gotoXY(unsigned int col, unsigned int row)
{
unsigned int rows, cols ;
if (mt_getScreenSize(&rows, &cols) == -1)
return -1 ;
if ((row > rows) || (row <= 0)||(col > cols) || (col <= 0))
return -1 ;
printf("\033[%d;%dH", row, col) ;
return 0 ;
}
/// Определяет размер экрана терминала
/// \param rows - кол-во строк
/// \param cols - кол-во столбцов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_getScreenSize(unsigned int *rows, unsigned int *cols){
winsize ws{} ;
if (ioctl(1, TIOCGWINSZ, &ws))
return -1 ;
* rows = ws.ws_row ;
* cols = ws.ws_col ;
return 0 ;
}
/// Устанавливает цвет последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setFGcolor(enum colors color){
printf("\033[38;5;%dm",color) ;
return 0 ;
}
/// Устанавливает цвет фона последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setBGcolor(enum colors color){
printf("\033[48;5;%dm",color) ;
return 0 ;
}
/// Возвращает цвета в стандартное состояние
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setDefaultColorSettings(){
printf("\033[0m") ;
return 0 ;
}
myUI.hpp
#ifndef MYUI_HPP
#define MYUI_HPP
#include
#include "myBigChars.hpp"
#include "myReadkey.hpp"
#include "simpleComputer.hpp"
int ui_initial() ;
int ui_update() ;
int setCurrMemPointer_to_ICounter() ;
int ui_moveCurrMemPointer(keys key) ;
int ui_setMCellValue() ;
int ui_saveMemory() ;
int ui_loadMemory() ;
int ui_setAccumulator() ;
int ui_setICounter() ;
bool checkCorrectInputHEX(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color);
int clearBuffIn() ;
#endif //MYUI_HPP
myUI.cpp
#include "myUI.hpp"
#include "myReadkey.hpp"
int8_t currMemCell = 0 ;
int drawingBoxes() ;
int drawingTexts() ;
int drawingMemory() ;
int drawingAccumulator() ;
int drawingInstructionCounter() ;
int drawingOperation() ;
int drawingFlags() ;
int drawingBigChar() ;
bool checkCorrectInputHEX(const char *buffer) ;
bool checkCorrectInputDEC(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color) ;
/// "Инициализация" интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_initial(){
currMemCell = 0 ;
if (rk_myTermSave())
return -1 ;
sc_memoryInit() ;
sc_accumulator &= (1 << 14) ;
sc_regInit() ;
sc_regSet(IGNORING_TACT_PULSES, true) ;
return 0 ;
}
/// Обновление интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_update(){
mt_clrScreen() ;
if (drawingBoxes())
return -1 ;
if (drawingTexts())
return -1 ;
if (drawingMemory())
return -1 ;
if (drawingAccumulator())
return -1 ;
if (drawingInstructionCounter())
return -1 ;
if (drawingOperation())
return -1 ;
if (drawingFlags())
return -1 ;
if (drawingBigChar())
return -1 ;
mt_gotoXY(1, 23) ;
printf("Input/Output:\n") ;
return 0 ;
}
/// Перемещение выделенной ячейки на значение ICounter
/// \return 0
int setCurrMemPointer_to_ICounter(){
currMemCell = sc_instructionCounter ;
return 0 ;
}
/// Перемещение выделенной ячейки
/// \param key - Клавиша
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_moveCurrMemPointer(keys key){
switch (key) {
case keys::KEY_UP: (currMemCell <= 9) ? (currMemCell = 90 + currMemCell) : (currMemCell -= 10) ; return 0 ;
case keys::KEY_RIGHT: (!((currMemCell + 1) % 10)) ? (currMemCell -= 9) : (currMemCell += 1) ; return 0 ;
case keys::KEY_DOWN: (currMemCell >= 90) ? (currMemCell = currMemCell - 90) : (currMemCell += 10) ; return 0 ;
case keys::KEY_LEFT: (!(currMemCell % 10)) ? (currMemCell += 9) : (currMemCell -= 1) ; return 0 ;
}
return -1 ;
}
int ui_setMCellValue(){
printf("Set the value of the cell under the number \033[38;5;%dm0x%02X\033[0m\n", colors::SOFT_GREEN, currMemCell) ;
printf("Enter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+')
i = 1 ;
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
number + 1 ;Приложение. Листинг
Makefile
d.PHONY: all clean run
COMPILER := g++
FLAGS := -fdiagnostics-color=always -Werror -MMD
SRC_SC := src/sc
BUILD_SC := build/sc
LIBS_SC := libs/sc
SRC_SA := src/sa
BUILD_SA := build/sa
SRC_SB := src/sb
BUILD_SB := build/sb
BIN := bin
SC := simpleComputer
SA := simpleAssembler
SB := simpleBasic
all: create $(BIN)/$(SC) $(BIN)/$(SA) $(BIN)/$(SB)
-include $((BUILD_SC)/*.d
-include $((BUILD_SA)/*.d
-include $((BUILD_SB)/*.d
sc: create $(BIN)/$(SC)
run_sc: sc
./$(BIN)/$(SC)
$(BIN)/$(SC): $(LIBS_SC)/libsimpleComputer.a $(LIBS_SC)/libmyTerm.a $(LIBS_SC)/libmyBigChars.a $(LIBS_SC)/libmyReadkey.a $(LIBS_SC)/libmyUI.a $(LIBS_SC)/libmyALU.a $(LIBS_SC)/libmyCU.a $(BUILD_SC)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SC) $(BUILD_SC)/main.o -L $(LIBS_SC) -lsimpleComputer -lmyUI -lmyTerm -lmyBigChars -lmyReadkey -lmyCU -lmyALU
$(BUILD_SC)/%.o: $(SRC_SC)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
$(LIBS_SC)/libsimpleComputer.a: $(BUILD_SC)/simpleComputer.o
ar cr $@ $^
$(LIBS_SC)/libmyTerm.a: $(BUILD_SC)/myTerm.o
ar cr $@ $^
$(LIBS_SC)/libmyBigChars.a: $(BUILD_SC)/myBigChars.o
ar cr $@ $^
$(LIBS_SC)/libmyReadkey.a: $(BUILD_SC)/myReadkey.o
ar cr $@ $^
$(LIBS_SC)/libmyUI.a: $(BUILD_SC)/myUI.o
ar cr $@ $^
$(LIBS_SC)/libmyALU.a: $(BUILD_SC)/myALU.o
ar cr $@ $^
$(LIBS_SC)/libmyCU.a: $(BUILD_SC)/myCU.o
ar cr $@ $^
sa: create $(BIN)/$(SA)
run_sa: create $(BIN)/$(SA)
./$(BIN)/$(SA)
$(BIN)/$(SA): $(BUILD_SA)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SA) $(BUILD_SA)/main.o
$(BUILD_SA)/%.o: $(SRC_SA)/%.cpps
$(COMPILER) $(FLAGS) -c $^ -o $@
sb: create $(BIN)/$(SB)
run_sb: create $(BIN)/$(SB)
./$(BIN)/$(SB)
$(BIN)/$(SB): $(BUILD_SB)/main.o
$(COMPILER) $(FLAGS) -o $(BIN)/$(SB) $(BUILD_SB)/main.o
$(BUILD_SB)/%.o: $(SRC_SB)/%.cpp
$(COMPILER) $(FLAGS) -c $^ -o $@
create:
mkdir -p $(BUILD_SC) $(BUILD_SA) $(BUILD_SB) $(LIBS_SC) $(BIN)
clean:
@rm -rf build libs $(BIN)
SimpleComputer
main.cpp
#include
#include "simpleComputer.hpp"
#include "myUI.hpp"
#include "myReadkey.hpp"
#include "myCU.hpp"
void signalHandler(int signal) ;
#include
int main(int argc, char const *argv[]){
ui_initial() ;
signal(SIGALRM, signalHandler) ;
signal(SIGUSR1, signalHandler) ;
bool zero, out, ignor, comm ;
keys key;
if (argc == 2){
sc_memoryLoad((char *)argv[1]) ;
}
else if (argc > 2){
ui_messageOutput((char *)"Exceeded the number of arguments", colors::RED) ;
return -1 ;
}
do {
sc_regGet(IGNORING_TACT_PULSES, &ignor);
ui_update() ;
rk_readKey(&key);
if (ignor){
sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
sc_regGet(OUT_OF_MEMORY, &out) ;
sc_regGet(INCORRECT_COMMAND, &comm) ;
if (zero || out || comm){
switch(key){
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
}
}
else{
switch(key){
case keys::KEY_UP:
ui_moveCurrMemPointer(keys::KEY_UP) ;
break ;
case keys::KEY_RIGHT:
ui_moveCurrMemPointer(keys::KEY_RIGHT) ;
break ;
case keys::KEY_DOWN:
ui_moveCurrMemPointer(keys::KEY_DOWN) ;
break ;
case keys::KEY_LEFT:
ui_moveCurrMemPointer(keys::KEY_LEFT) ;
break ;
case keys::KEY_L:
ui_initial() ;
ui_loadMemory() ;
break ;
case keys::KEY_S:
ui_saveMemory() ;
break ;
case keys::KEY_R:
sc_regInit() ;
raise(SIGALRM) ;
break ;
case keys::KEY_T:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
CU() ;
break ;
case keys::KEY_I:
raise(SIGUSR1) ;
break ;
case keys::KEY_F5:
ui_setAccumulator() ;
break ;
case keys::KEY_F6:
ui_setICounter() ;
break ;
case keys::KEY_ENTER:
ui_setMCellValue() ;
break ;
}
}
}
else
if (key == keys::KEY_I)
raise(SIGUSR1) ;
} while(key != keys::KEY_ESC) ;
return 0 ;
}
void signalHandler(int signal){
switch (signal) {
case SIGALRM:
setCurrMemPointer_to_ICounter() ;
ui_update() ;
if (CU()){
sc_regSet(IGNORING_TACT_PULSES, true);
ui_update() ;
alarm(0) ;
}
else
alarm(1) ;
rk_myTermRegime(false, 0, 0, false, false) ;
break ;
case SIGUSR1:
alarm(0) ;
ui_initial() ;
break ;
default:
break ;
}
}
simpleComputer.hpp
#ifndef SIMPLECOMPUTER_HPP
#define SIMPLECOMPUTER_HPP
#include
#define OVERFLOW 0 // Переполнение при выполнении операции
#define DIVISION_ERR_BY_ZERO 1 // Ошибка деления на 0
#define OUT_OF_MEMORY 2 // Ошибка выхода за границы памяти
#define IGNORING_TACT_PULSES 3 // Игнорирование тактовых импульсов
#define INCORRECT_COMMAND 4 // Указана неверная команда
const short int SC_REG_SIZE = 5 ;
const short int SC_MEM_SIZE = 100 ;
extern unsigned short int sc_accumulator ;
extern uint8_t sc_instructionCounter ;
int sc_memoryInit () ;
int sc_memorySet (unsigned short int address, unsigned short int value) ;
int sc_memoryGet (unsigned short int address, unsigned short int * value) ;
int sc_memorySave (char* filename) ;
int sc_memoryLoad (char* filename) ;
int sc_regInit () ;
int sc_regSet (int8_t reg, bool value) ;
int sc_regGet (int8_t reg, bool * value) ;
int sc_commandEncode (unsigned short int command, unsigned short int operand, unsigned short int * value) ;
int sc_commandDecode (unsigned short int value, unsigned short int * command, unsigned short int * operand) ;
#endif //SIMPLECOMPUTER_HPP
simpleComputer.cpp
#include "simpleComputer.hpp"
unsigned short int sc_memory[SC_MEM_SIZE] ;
uint8_t sc_regFLAGS ;
unsigned short int sc_accumulator ;
uint8_t sc_instructionCounter ;
/// Инициализирует оперативную память SC, задавая всем её ячейкам нулевые значения
/// \return 0
int sc_memoryInit()
{
sc_instructionCounter = 0 ;
for (unsigned short & mem : sc_memory)
mem = 0 ;
return 0 ;
}
/// Задает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySet(unsigned short int address, unsigned short int value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
sc_memory[address] = value ;
return 0 ;
}
/// Возвращает значение указанной ячейки памяти
/// \param address - ячейка памяти
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryGet(unsigned short int address, unsigned short int * value){
if (address >= SC_MEM_SIZE){
sc_regSet(OUT_OF_MEMORY, true) ;
return -1 ;
}
*value = sc_memory[address] ;
return 0 ;
}
/// Сохраняет содержимое памяти в файл в бинарном виде
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memorySave(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "wb"))){
return -1 ;
}
fwrite(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Загружает из указанного файла содержимое оперативной памяти
/// \param filename - имя файла
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_memoryLoad(char* filename){
FILE * fb ;
if (!(fb = fopen(filename, "rb"))){
return -1 ;
}
fread(sc_memory, sizeof(sc_memory), 1, fb) ;
fclose(fb) ;
return 0 ;
}
/// Инициализирует регистр флагов нулевым значением
/// \return 0
int sc_regInit(){
sc_regFLAGS = 0 ;
return 0 ;
}
/// Устанавливает значение указанного регистра флагов
/// \param reg - флаг
/// \param value - значение
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int sc_regSet(int8_t reg, bool value){
if (reg < 0 || reg >= SC_REG_SIZE)
return -1 ;
value == 1 ? (sc_regFLAGS |= (1 << reg)) : (sc_regFLAGS &=
#include
enum colors {
RED = 196,
PEACH = 203,
GREEN = 10,
SOFT_GREEN =192,
BLUE = 20,
BLACK = 16,
GRAY = 240,
WHITE = 15,
DEFAULT = 0};
int mt_clrScreen () ;
int mt_gotoXY(unsigned int col,unsigned int row) ;
int mt_getScreenSize(unsigned int *rows, unsigned int* cols) ;
int mt_setFGcolor(enum colors color) ;
int mt_setBGcolor(enum colors color) ;
int mt_setDefaultColorSettings() ;
#endif //MYTERM_HPP
myTerm.cpp
#include "myTerm.hpp"
/// Производит очистку и перемещение курсора в левый верхний угол экрана
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_clrScreen (){
printf("\033[H\033[2J") ;
return 0 ;
}
/// Перемещает курсор в указанную позицию
/// \param col - столбец
/// \param row - строка
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_gotoXY(unsigned int col, unsigned int row)
{
unsigned int rows, cols ;
if (mt_getScreenSize(&rows, &cols) == -1)
return -1 ;
if ((row > rows) || (row <= 0)||(col > cols) || (col <= 0))
return -1 ;
printf("\033[%d;%dH", row, col) ;
return 0 ;
}
/// Определяет размер экрана терминала
/// \param rows - кол-во строк
/// \param cols - кол-во столбцов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_getScreenSize(unsigned int *rows, unsigned int *cols){
winsize ws{} ;
if (ioctl(1, TIOCGWINSZ, &ws))
return -1 ;
* rows = ws.ws_row ;
* cols = ws.ws_col ;
return 0 ;
}
/// Устанавливает цвет последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setFGcolor(enum colors color){
printf("\033[38;5;%dm",color) ;
return 0 ;
}
/// Устанавливает цвет фона последующих выводимых символов
/// \param color - цвет из перечисления colors
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setBGcolor(enum colors color){
printf("\033[48;5;%dm",color) ;
return 0 ;
}
/// Возвращает цвета в стандартное состояние
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int mt_setDefaultColorSettings(){
printf("\033[0m") ;
return 0 ;
}
myUI.hpp
#ifndef MYUI_HPP
#define MYUI_HPP
#include
#include "myBigChars.hpp"
#include "myReadkey.hpp"
#include "simpleComputer.hpp"
int ui_initial() ;
int ui_update() ;
int setCurrMemPointer_to_ICounter() ;
int ui_moveCurrMemPointer(keys key) ;
int ui_setMCellValue() ;
int ui_saveMemory() ;
int ui_loadMemory() ;
int ui_setAccumulator() ;
int ui_setICounter() ;
bool checkCorrectInputHEX(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color);
int clearBuffIn() ;
#endif //MYUI_HPP
myUI.cpp
#include "myUI.hpp"
#include "myReadkey.hpp"
int8_t currMemCell = 0 ;
int drawingBoxes() ;
int drawingTexts() ;
int drawingMemory() ;
int drawingAccumulator() ;
int drawingInstructionCounter() ;
int drawingOperation() ;
int drawingFlags() ;
int drawingBigChar() ;
bool checkCorrectInputHEX(const char *buffer) ;
bool checkCorrectInputDEC(const char *buffer) ;
int ui_messageOutput(char *str, enum colors color) ;
/// "Инициализация" интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_initial(){
currMemCell = 0 ;
if (rk_myTermSave())
return -1 ;
sc_memoryInit() ;
sc_accumulator &= (1 << 14) ;
sc_regInit() ;
sc_regSet(IGNORING_TACT_PULSES, true) ;
return 0 ;
}
/// Обновление интерфейса пользователя
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_update(){
mt_clrScreen() ;
if (drawingBoxes())
return -1 ;
if (drawingTexts())
return -1 ;
if (drawingMemory())
return -1 ;
if (drawingAccumulator())
return -1 ;
if (drawingInstructionCounter())
return -1 ;
if (drawingOperation())
return -1 ;
if (drawingFlags())
return -1 ;
if (drawingBigChar())
return -1 ;
mt_gotoXY(1, 23) ;
printf("Input/Output:\n") ;
return 0 ;
}
/// Перемещение выделенной ячейки на значение ICounter
/// \return 0
int setCurrMemPointer_to_ICounter(){
currMemCell = sc_instructionCounter ;
return 0 ;
}
/// Перемещение выделенной ячейки
/// \param key - Клавиша
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int ui_moveCurrMemPointer(keys key){
switch (key) {
case keys::KEY_UP: (currMemCell <= 9) ? (currMemCell = 90 + currMemCell) : (currMemCell -= 10) ; return 0 ;
case keys::KEY_RIGHT: (!((currMemCell + 1) % 10)) ? (currMemCell -= 9) : (currMemCell += 1) ; return 0 ;
case keys::KEY_DOWN: (currMemCell >= 90) ? (currMemCell = currMemCell - 90) : (currMemCell += 10) ; return 0 ;
case keys::KEY_LEFT: (!(currMemCell % 10)) ? (currMemCell += 9) : (currMemCell -= 1) ; return 0 ;
}
return -1 ;
}
int ui_setMCellValue(){
printf("Set the value of the cell under the number \033[38;5;%dm0x%02X\033[0m\n", colors::SOFT_GREEN, currMemCell) ;
printf("Enter value in \033[38;5;%dmHEX\033[0m format > ", colors::PEACH);
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+')
i = 1 ;
else{
res |= (1 << 14) ;
if (buffer[0] == '-') {
i = 1 ;
res |= (1 << 13) ;
}
else
i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
ui_messageOutput((char *)"Invalid input", colors::RED) ;
return -1 ;
}
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if ((number >> 8) > 0x7F){
ui_messageOutput((char *)"The command cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
if ((number & 0xFF) > 0x7F){
ui_messageOutput((char *)"The operand cannot be more than 7 bits (0x7F)", colors::RED) ;
return -1 ;
}
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value))
return -1 ;
res |= value ;
}
else{
if(number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
ui_messageOutput((char *)"The valid range for the value of the number from -0x2000 to 0x1FFF inclusive", colors::RED) ;
return -1 ;
}
if (buffer[0] == '-'){
number =
if (!((number >> 13) & 1))
res &=
if (!((number >> 13) & 1))
res &=
else
printf(" %04X", tmp & 0x1FFF) ;
else
printf("+%04X", tmp) ;
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка accumulator
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingAccumulator(){
mt_gotoXY(70,2) ;
// bool over ;
// sc_regGet(OVERFLOW, &over) ;
// if (over){
// mt_setFGcolor(colors::PEACH) ;
// printf(" over") ;
// mt_setDefaultColorSettings() ;
// }
// else{
if((sc_accumulator >> 14) & 1)
if((sc_accumulator >> 13) & 1)
printf("-%04X", (
else
tmp &= 0x1FFF ;
left = tmp >> 8 ;
right = tmp & 0xFF ;
negative ? printf("-%02X:%02X", left, right) : printf(" %02X:%02X", left, right) ;
}
return 0 ;
}
/// Отрисовка instructionCounter
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingInstructionCounter(){
mt_gotoXY(71,5) ;
// bool over, zero, out, comm ;
// sc_regGet(OVERFLOW, &over) ;
// sc_regGet(DIVISION_ERR_BY_ZERO, &zero) ;
// sc_regGet(OUT_OF_MEMORY, &out) ;
// sc_regGet(INCORRECT_COMMAND, &comm) ;
// mt_gotoXY(71,5) ;
// if (over || zero || out || comm){
// mt_setFGcolor(colors::SOFT_GREEN) ;
// printf("null") ;
// mt_setDefaultColorSettings() ;
// }
// else
printf("%04X", sc_instructionCounter) ;
return 0 ;
}
/// Отрисовка флагов
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingFlags(){
char tmp[] = {'O', 'Z', 'M', 'I', 'C'};
for (int i = 0 ; i < SC_REG_SIZE ; ++i) {
bool value ;
if (sc_regGet(i, &value))
return -1 ;
mt_gotoXY(68 + (i * 2), 11) ;
if (value){
mt_setFGcolor(colors::PEACH) ;
printf("%c", tmp[i]) ;
}
else{
mt_setFGcolor(colors::GRAY) ;
printf("%c", tmp[i]) ;
}
mt_setDefaultColorSettings() ;
}
return 0 ;
}
/// Отрисовка "BigChar'ов"
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int drawingBigChar(){
unsigned short int tmp ;
sc_memoryGet(currMemCell, &tmp) ;
if(!((tmp >> 14) & 1))
bc_printBigChar(bc[16], 2, 14, GREEN) ;
else if((tmp >> 13) & 1){
bc_printBigChar(bc[17], 2, 14, GREEN) ;
tmp = (
#include
#include
extern termios save;
enum keys
{
KEY_L,
KEY_S,
KEY_R,
KEY_T,
KEY_I,
KEY_F5,
KEY_F6 ,
KEY_UP,
KEY_DOWN,
KEY_RIGHT,
KEY_LEFT,
KEY_ESC,
KEY_ENTER,
KEY_OTHER,
};
int rk_readKey(enum keys *key) ;
int rk_myTermSave() ;
int rk_myTermRestore() ;
int rk_myTermRegime (bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint) ;
#endif //MYREADKEY_HPP
myReadkey.cpp
#include "myReadkey.hpp"
termios save;
/// Возвращающую первую клавишу, которую нажал пользователь
/// \param key - Адрес переменной, в которую возвращается номер нажатой клавиши
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_readKey (enum keys * key){
fflush(stdout) ; // очистка потока вывода
char buffer[5] = "\0" ;
rk_myTermRegime(false, 0, 0, false, false) ;
read(fileno(stdin), buffer, 5) ;
rk_myTermRestore() ;
if (buffer[0] == '\033')
if (buffer[1] == '\0')
*key = KEY_ESC ;
else if (buffer[1] == '[')
if (buffer[2] == 'A' and buffer[3] == '\0')
*key = KEY_UP ;
else if (buffer[2] == 'B' and buffer[3] == '\0')
*key = KEY_DOWN ;
else if (buffer[2] == 'C' and buffer[3] == '\0')
*key = KEY_RIGHT ;
else if (buffer[2] == 'D' and buffer[3] == '\0')
*key = KEY_LEFT ;
else if (buffer[2] == '1' and buffer[3] == '5')
*key = KEY_F5 ;
else if (buffer[2] == '1' and buffer[3] == '7')
*key = KEY_F6 ;
else
*key = KEY_OTHER ;
else
*key = KEY_OTHER ;
else if (buffer[0] == '\n' and buffer[1] == '\0')
*key = KEY_ENTER ;
else
if ((buffer[0] == 'l' or buffer[0] == 'L') and buffer[1] == '\0')
*key = KEY_L ;
else if ((buffer[0] == 's' or buffer[0] == 'S') and buffer[1] == '\0')
*key = KEY_S ;
else if ((buffer[0] == 'r' or buffer[0] == 'R') and buffer[1] == '\0')
*key = KEY_R ;
else if ((buffer[0] == 't' or buffer[0] == 'T') and buffer[1] == '\0')
*key = KEY_T ;
else if ((buffer[0] == 'i' or buffer[0] == 'I') and buffer[1] == '\0')
*key = KEY_I ;
else
*key = KEY_OTHER ;
return 0 ;
}
/// Функция, сохраняющая текущие параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermSave(){
if (tcgetattr(fileno(stdin), &save))
return -1 ;
return 0 ;
}
/// Функция, восстанавливающая сохраненные параметры терминала
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRestore(){
tcsetattr(fileno(stdin), TCSAFLUSH, &save) ;
return 0 ;
}
/// Функция, переключающая режим работы терминала (канонический / неканонический)
/// \param regime
/// \param vtime
/// \param vmin
/// \param echo
/// \param sigint
/// \return 0 - в случае успешного выполнения, -1 - в случае ошибки
int rk_myTermRegime(bool regime, unsigned int vtime, unsigned int vmin, bool echo, bool sigint){
termios curr{} ;
tcgetattr(fileno(stdin), &curr) ;
if(regime)
curr.c_lflag |= ICANON ;
else{
curr.c_lflag &=
sigint ? (curr.c_lflag |= ISIG) : (curr.c_lflag &=
curr.c_cc[VMIN] = vmin ;
curr.c_cc[VTIME] = vtime ;
}
tcsetattr(0,TCSAFLUSH,&curr) ;
return 0 ;
}
commands.hpp
#ifndef COMMANDS_HPP
#define COMMANDS_HPP
#define READ 0x10
#define WRITE 0x11
#define LOAD 0x20
#define STORE 0x21
#define ADD 0x30
#define SUB 0x31
#define DIVIDE 0x32
#define MUL 0x33
#define JUMP 0x40
#define JNEG 0x41
#define JZ 0x42
#define HALT 0x43
#define RCR 0x63
#endif //COMMANDS_HPP
myCU.hpp
#ifndef CU_HPP
#define CU_HPP
#include "commands.hpp"
#include "simpleComputer.hpp"
#include "myTerm.hpp"
#include "myUI.hpp"
#include "myALU.hpp"
int CU() ;
#endif //CU_HPP
myCU.cpp
#include "myCU.hpp"
int cu_read(unsigned short int operand) ;
int cu_write(unsigned short int operand) ;
int cu_load(unsigned short int operand) ;
int cu_store(unsigned short int operand) ;
int cu_jump(unsigned short int operand) ;
int cu_jneg(unsigned short int operand) ;
int cu_jz(unsigned short int operand) ;
int CU (){
unsigned short int command = 0;
unsigned short int operand = 0;
unsigned short int currCell;
sc_memoryGet(sc_instructionCounter, &currCell) ;
if (sc_commandDecode(currCell, &command, &operand)){
return -1 ;
}
switch (command) {
case READ:
if (cu_read(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case WRITE:
if (cu_write(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case LOAD :
if (cu_load(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case STORE :
if (cu_store(operand))
return -1 ;
else
sc_instructionCounter++ ;
break ;
case JUMP :
if (cu_jump(operand))
return -1 ;
break ;
case JNEG :
if (cu_jneg(operand))
return -1 ;
break ;
case JZ :
if (cu_jz(operand))
return -1 ;
break ;
case HALT :
return -1 ;
break ;
default:
if (ALU(command, operand))
return -1 ;
break ;
}
return 0 ;
}
int cu_read(unsigned short int operand){
rk_myTermRestore() ;
printf("Enter value of cell[\033[38;5;%dm0x%02X\033[0m] in \033[38;5;%dmHEX\033[0m format > ", colors::SOFT_GREEN, operand, colors::PEACH) ;
char buffer[10] ;
fgets(buffer, 10, stdin) ;
if (buffer[strlen(buffer) - 1] != '\n')
clearBuffIn(); // очистка потока ввода
else
buffer[strlen(buffer) - 1] = '\0' ;
rk_myTermRegime(false, 0, 0, false, false) ;
unsigned short int res = 0 ;
int i ;
if (buffer[0] == '+' or buffer[0] == '-')
i = 1 ;
else{
res |= (1 << 14) ;
(buffer[0] == '-') ? (res |= (1 << 13)) : i = 0 ;
}
if (!checkCorrectInputHEX(&buffer[i])){
res |= (1 << 15) ;
}
else{
long int number ;
char * tmp ;
number = strtol(&buffer[i], &tmp, 16) ;
if (buffer[0] == '+') { // Проверка на команду
if (number > 0x3FFF)
res |= (1 << 15) ;
else
{
number &= 0x3FFF ;
unsigned short int value = 0;
if (sc_commandEncode((unsigned short int)((number >> 8)), (unsigned short int)(number & 0xFF), &value)){
res |= (1 << 15) ;
}
else
res |= value ;
}
}
else{
if (number > 0x2000 or (number > 0x1FFF and buffer[0] != '-') ){
res |= (1 << 15) ;
}
if (buffer[0] == '-'){
number =
}
number &= 0x1FFF ;
res |= number ;
}
}
if (sc_memorySet(operand, (unsigned short int)res))
return -1 ;
return 0 ;
}
int cu_write(unsigned short int operand){
unsigned short int value;
if(sc_memoryGet(operand, &value)){
return -1 ;
}
printf("Value in a cell [\033[38;5;%dm0x%02X\033[0m] < ", colors::SOFT_GREEN, operand) ;
if ((value >> 14) & 1)
if ((value >> 13) & 1)
printf("-%04X", (
else
value = (
accumulator =
}
else if (((accumulator >> 13) & 1) or ((value >> 13) & 1)) { // Если одно из чисел отрицательно
res = accumulator + value ;
}
else{
res = accumulator + value ;
if (res > 0x1FFF){
sc_regSet(OVERFLOW, true) ;
}
}
res |= (1 << 14) ;
sc_accumulator = res ;
return 0 ;
}
int alu_divide(unsigned short int operand){
unsigned short int value,accumulator, res ;
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
bool negative = 0 ;
accumulator = sc_accumulator & 0x3FFF ;
value &= 0x3FFF;
if ((accumulator >> 13) & 1){
negative = !negative ;
accumulator =
}
value &= 0x3FFF ;
if (value == 0){
sc_regSet(DIVISION_ERR_BY_ZERO, true) ;
return -1 ;
}
res = accumulator / value ;
if (negative){
if (res > 0x2000){
sc_regSet(OVERFLOW, true) ;
}
res = (
}
accumulator &= 0x1FFF ;
if ((value >> 13) & 1){
negative = !negative ;
value =
res |= (1 << 14) ;
sc_accumulator = res ;
}
else {
if (res > 0x1FFF){
sc_regSet(OVERFLOW, true) ;
}
res |= (1 << 14) ;
sc_accumulator = res ;
}
return 0 ;
}
int alu_rcr(unsigned short int operand){
unsigned short int res, value ;
if (sc_memoryGet(operand, &value))
return -1 ;
if (!((value >> 14) & 1)){
sc_regSet(INCORRECT_COMMAND, true) ;
return -1 ;
}
bool negative = (value >> 13) & 1;
if (negative) // Отрицательное
value =
}
else{
if (res > 0x1FFF)
sc_regSet(OVERFLOW, true) ;
}
res |= (1 << 14) ;
sc_accumulator = res ;
return 0 ;
}