c++/rgb-assembler/rgb-assembler.cpp
author František Kučera <franta-hg@frantovo.cz>
Sat, 23 Dec 2017 17:52:32 +0100
changeset 18 4975c24cc361
parent 17 8f0a5552db78
child 19 17785b69430d
permissions -rw-r--r--
check memory bounds in read() and write()
franta-hg@0
     1
#include <cstdlib>
franta-hg@0
     2
#include <iostream>
franta-hg@0
     3
#include <wchar.h>
franta-hg@0
     4
#include <locale.h>
franta-hg@0
     5
#include <cstring>
franta-hg@0
     6
franta-hg@6
     7
#include <chrono>
franta-hg@6
     8
#include <thread>
franta-hg@6
     9
franta-hg@0
    10
using namespace std;
franta-hg@0
    11
franta-hg@0
    12
typedef uint16_t address_t;
franta-hg@17
    13
typedef uint8_t octet_t;
franta-hg@0
    14
typedef uint8_t command_t;
franta-hg@6
    15
typedef uint8_t sleep_t;
franta-hg@10
    16
typedef uint8_t color_t;
franta-hg@13
    17
typedef uint8_t led_t;
franta-hg@0
    18
franta-hg@12
    19
// TODO: strong typedefs http://www.boost.org/doc/libs/1_61_0/libs/serialization/doc/strong_typedef.html ?
franta-hg@12
    20
franta-hg@0
    21
const address_t MEMORY_SIZE = 1024;
franta-hg@0
    22
franta-hg@13
    23
/**
franta-hg@13
    24
 * Skip to the given address.
franta-hg@13
    25
 * parameter: address_t
franta-hg@13
    26
 */
franta-hg@5
    27
const command_t CMD_GOTO = 0x70;
franta-hg@13
    28
franta-hg@13
    29
/**
franta-hg@15
    30
 * Compare values on two addresses and go to one of given three addresses.
franta-hg@15
    31
 * parameter: address_t a
franta-hg@15
    32
 * parameter: address_t b
franta-hg@15
    33
 * parameter: address_t GOTO target when a == b
franta-hg@15
    34
 * parameter: address_t GOTO target when a > b
franta-hg@15
    35
 * parameter: address_t GOTO target when a < b
franta-hg@15
    36
 */
franta-hg@15
    37
const command_t CMD_GOTO_COMPARE = 0x80;
franta-hg@15
    38
franta-hg@15
    39
/**
franta-hg@13
    40
 * Wait given time in ms.
franta-hg@13
    41
 * parameter: sleep_t
franta-hg@13
    42
 */
franta-hg@5
    43
const command_t CMD_SLEEP = 0xFF;
franta-hg@13
    44
franta-hg@13
    45
/**
franta-hg@13
    46
 * Set RGB LED color.
franta-hg@13
    47
 * parameter: led_t LED number
franta-hg@13
    48
 * parameter: color_t red
franta-hg@13
    49
 * parameter: color_t green
franta-hg@13
    50
 * parameter: color_t blue
franta-hg@13
    51
 */
franta-hg@10
    52
const command_t CMD_COLOR = 0xAA;
franta-hg@13
    53
franta-hg@13
    54
/**
franta-hg@13
    55
 * Stop program.
franta-hg@13
    56
 */
franta-hg@5
    57
const command_t CMD_END = 0xED;
franta-hg@13
    58
franta-hg@13
    59
/**
franta-hg@14
    60
 * Increase value at given address
franta-hg@14
    61
 * parameter: address_t
franta-hg@14
    62
 */
franta-hg@14
    63
const command_t CMD_INCREMENT = 0x11;
franta-hg@14
    64
franta-hg@14
    65
/**
franta-hg@14
    66
 * Decrease value at given address
franta-hg@14
    67
 * parameter: address_t
franta-hg@14
    68
 */
franta-hg@14
    69
const command_t CMD_DECREMENT = 0x12;
franta-hg@14
    70
franta-hg@14
    71
/**
franta-hg@13
    72
 * Placeholder for unsupported command.
franta-hg@13
    73
 * Just for testing.
franta-hg@13
    74
 */
franta-hg@13
    75
const command_t CMD_INVALID = 0x1;
franta-hg@0
    76
franta-hg@15
    77
// TODO: more commands, better numbers
franta-hg@15
    78
franta-hg@18
    79
template<typename T> T logMemoryError(const address_t &index) {
franta-hg@18
    80
	wprintf(L"memory error: index = %d, sizeof(T) = %d, MEMORY_SIZE = %d\n", index, sizeof (T), MEMORY_SIZE);
franta-hg@18
    81
	// TODO: return error value or throw exception
franta-hg@18
    82
	return T();
franta-hg@18
    83
}
franta-hg@18
    84
franta-hg@1
    85
/**
franta-hg@8
    86
 * Reads data on given position in memory and increments the index (position).
franta-hg@17
    87
 * 
franta-hg@17
    88
 * @param memory array of bytes / octets
franta-hg@17
    89
 * @param index offset in same units as memory type
franta-hg@17
    90
 * @return value found at given position
franta-hg@1
    91
 */
franta-hg@17
    92
template<typename T> T read(octet_t * memory, address_t &index) {
franta-hg@18
    93
	// TODO: map higher memory to static hardcoded areas or peripherals
franta-hg@18
    94
	if (index + sizeof (T) <= MEMORY_SIZE) {
franta-hg@18
    95
		T * value = reinterpret_cast<T*> (memory + index);
franta-hg@18
    96
		index += sizeof (T);
franta-hg@18
    97
		return *value;
franta-hg@18
    98
	} else {
franta-hg@18
    99
		return logMemoryError<T>(index);
franta-hg@18
   100
	}
franta-hg@0
   101
}
franta-hg@0
   102
franta-hg@9
   103
/**
franta-hg@9
   104
 * Writes data to given position in memory and increments the index (position).
franta-hg@17
   105
 * @param memory array of bytes / octets
franta-hg@17
   106
 * @param index offset in same units as memory type
franta-hg@17
   107
 * @param value value to be written at given position
franta-hg@9
   108
 */
franta-hg@18
   109
template<typename T> T write(octet_t * memory, address_t &index, const T value) {
franta-hg@18
   110
	if (index + sizeof (T) <= MEMORY_SIZE) {
franta-hg@18
   111
		T * m = reinterpret_cast<T*> (memory + index);
franta-hg@18
   112
		*m = value;
franta-hg@18
   113
		index += sizeof (value);
franta-hg@18
   114
	} else {
franta-hg@18
   115
		return logMemoryError<T>(index);
franta-hg@18
   116
	}
franta-hg@6
   117
}
franta-hg@6
   118
franta-hg@0
   119
int main(int argc, char* argv[]) {
franta-hg@0
   120
franta-hg@0
   121
	setlocale(LC_ALL, "");
franta-hg@0
   122
franta-hg@17
   123
	octet_t * memory = (octet_t*) malloc(MEMORY_SIZE);
franta-hg@0
   124
franta-hg@16
   125
	// Sample program / data:
franta-hg@16
   126
	// TODO: load bytes from file, stdin, serial port, network…
franta-hg@2
   127
	{
franta-hg@2
   128
		address_t a = 0;
franta-hg@9
   129
		write<command_t>(memory, a, CMD_SLEEP);
franta-hg@9
   130
		write<sleep_t>(memory, a, 255);
franta-hg@9
   131
		write<command_t>(memory, a, CMD_SLEEP);
franta-hg@9
   132
		write<sleep_t>(memory, a, 10);
franta-hg@9
   133
		write<command_t>(memory, a, CMD_SLEEP);
franta-hg@9
   134
		write<sleep_t>(memory, a, 255);
franta-hg@9
   135
		write<command_t>(memory, a, CMD_GOTO);
franta-hg@15
   136
		write<address_t>(memory, a, a + sizeof (address_t) + 2 * sizeof (command_t));
franta-hg@11
   137
		write<command_t>(memory, a, CMD_INVALID);
franta-hg@11
   138
		write<command_t>(memory, a, CMD_INVALID);
franta-hg@9
   139
		write<command_t>(memory, a, CMD_SLEEP);
franta-hg@9
   140
		write<sleep_t>(memory, a, 255);
franta-hg@10
   141
		write<command_t>(memory, a, CMD_COLOR);
franta-hg@13
   142
		write<led_t>(memory, a, 23);
franta-hg@11
   143
		write<color_t>(memory, a, 0);
franta-hg@11
   144
		write<color_t>(memory, a, 200);
franta-hg@11
   145
		write<color_t>(memory, a, 255);
franta-hg@14
   146
		write<command_t>(memory, a, CMD_INCREMENT);
franta-hg@14
   147
		write<address_t>(memory, a, 0);
franta-hg@14
   148
		write<command_t>(memory, a, CMD_DECREMENT);
franta-hg@14
   149
		write<address_t>(memory, a, 0);
franta-hg@15
   150
		write<command_t>(memory, a, CMD_GOTO_COMPARE);
franta-hg@15
   151
		write<address_t>(memory, a, 0);
franta-hg@15
   152
		write<address_t>(memory, a, 0 + sizeof (command_t) + sizeof (sleep_t));
franta-hg@15
   153
		write<address_t>(memory, a, a - 3 * sizeof (address_t) - 2 * sizeof (command_t));
franta-hg@15
   154
		write<address_t>(memory, a, 0);
franta-hg@15
   155
		write<address_t>(memory, a, a + sizeof (address_t));
franta-hg@9
   156
		write<command_t>(memory, a, CMD_END);
franta-hg@2
   157
	}
franta-hg@0
   158
franta-hg@2
   159
	for (address_t i = 0; i < MEMORY_SIZE;) {
franta-hg@11
   160
		wprintf(L"command %*d = ", 4, i);
franta-hg@16
   161
		command_t command = read<command_t>(memory, i);
franta-hg@16
   162
		wprintf(L"%02X  ", command);
franta-hg@0
   163
franta-hg@16
   164
		switch (command) {
franta-hg@0
   165
			case CMD_GOTO:
franta-hg@12
   166
			{
franta-hg@8
   167
				i = read<address_t>(memory, i);
franta-hg@11
   168
				wprintf(L"GOTO %*d\n", 5, i);
franta-hg@0
   169
				break;
franta-hg@12
   170
			}
franta-hg@0
   171
			case CMD_SLEEP:
franta-hg@12
   172
			{
franta-hg@12
   173
				sleep_t delay = read<sleep_t>(memory, i);
franta-hg@11
   174
				wprintf(L"SLEEP %*d ms\n", 4, delay);
franta-hg@11
   175
				this_thread::sleep_for(chrono::milliseconds(delay));
franta-hg@0
   176
				break;
franta-hg@12
   177
			}
franta-hg@10
   178
			case CMD_COLOR:
franta-hg@12
   179
			{
franta-hg@13
   180
				led_t led = read<led_t>(memory, i);
franta-hg@12
   181
				color_t r = read<color_t>(memory, i);
franta-hg@12
   182
				color_t g = read<color_t>(memory, i);
franta-hg@12
   183
				color_t b = read<color_t>(memory, i);
franta-hg@13
   184
				wprintf(L"COLOR  %02X %02X %02X → %d\n", r, g, b, led);
franta-hg@10
   185
				break;
franta-hg@12
   186
			}
franta-hg@14
   187
			case CMD_INCREMENT:
franta-hg@14
   188
			case CMD_DECREMENT:
franta-hg@14
   189
			{
franta-hg@14
   190
				address_t address = read<address_t>(memory, i);
franta-hg@14
   191
				address_t address_r = address;
franta-hg@14
   192
				address_t address_w = address_r;
franta-hg@17
   193
				octet_t value = read<octet_t>(memory, address_r);
franta-hg@16
   194
				value = command == CMD_INCREMENT ? value + 1 : value - 1;
franta-hg@17
   195
				write<octet_t>(memory, address_w, value);
franta-hg@16
   196
				wprintf(L"%sCREMENT %*d → %02X\n", (command == CMD_INCREMENT ? "IN" : "DE"), 5, address, value);
franta-hg@14
   197
				break;
franta-hg@14
   198
			}
franta-hg@15
   199
			case CMD_GOTO_COMPARE:
franta-hg@15
   200
			{
franta-hg@15
   201
				address_t aa = read<address_t>(memory, i);
franta-hg@15
   202
				address_t ab = read<address_t>(memory, i);
franta-hg@15
   203
				address_t eq = read<address_t>(memory, i);
franta-hg@15
   204
				address_t gt = read<address_t>(memory, i);
franta-hg@15
   205
				address_t lt = read<address_t>(memory, i);
franta-hg@15
   206
franta-hg@17
   207
				octet_t a = read<octet_t>(memory, aa);
franta-hg@17
   208
				octet_t b = read<octet_t>(memory, ab);
franta-hg@15
   209
franta-hg@16
   210
				if (a == b) i = eq;
franta-hg@16
   211
				else if (a > b) i = gt;
franta-hg@16
   212
				else i = lt;
franta-hg@16
   213
franta-hg@15
   214
				wprintf(L"GOTO COMPARE  a = %02X, b = %02X, eq = %d, gt = %d, lt = %d → %d\n", a, b, eq, gt, lt, i);
franta-hg@15
   215
				break;
franta-hg@15
   216
			}
franta-hg@0
   217
			case CMD_END:
franta-hg@12
   218
			{
franta-hg@11
   219
				wprintf(L"END\n");
franta-hg@2
   220
				i = MEMORY_SIZE;
franta-hg@0
   221
				break;
franta-hg@12
   222
			}
franta-hg@11
   223
			default:
franta-hg@12
   224
			{
franta-hg@11
   225
				wprintf(L"invalid command\n");
franta-hg@12
   226
			}
franta-hg@0
   227
		}
franta-hg@0
   228
franta-hg@0
   229
	}
franta-hg@0
   230
franta-hg@7
   231
	free(memory);
franta-hg@7
   232
	memory = nullptr;
franta-hg@0
   233
	wprintf(L"all done\n");
franta-hg@0
   234
	return 0;
franta-hg@0
   235
}
franta-hg@0
   236