aboutsummaryrefslogtreecommitdiff
path: root/src/render.c
blob: 128ce3b110e40469798b823ea240c5116b7a64f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <assert.h>
#include <stdio.h>
#include "types.h"
#include "memory.h"
#include "process.h"
#include "render.h"

#define MAX_ZOOM 0x10000
#define BLOCK_FLAG 0x40
#define IP_FLAG 0x80

static void apply_flag(
	uint32 origin, uint32 max_pos, uint32 cell_size, uint32 address,
	uint32 flag, uint8_p buffer
) {
	if (address >= origin && address < max_pos) {
		/* Flag falls inside rendered image. We can 'and' the bit to the
		corresponding pixel.
		*/
		uint32 pixel = (address - origin) / cell_size;
		buffer[pixel] |= flag;
	}
}

void sal_ren_get_image(
	uint32 origin, uint32 cell_size, uint32 buff_size, uint8_p buffer
) {
	/* Render a 1D image of a given section of memory, at a given resolution
	(zoom) and store it in a pre-allocated 'buffer'.

	On the Salis python handler we draw memory as a 1D 'image' on the WORLD
	page. If we were to render this image directly on python, it would be
	excruciatingly slow, as we have to iterate over large areas of memory!
	Therefore, this memory module comes with a built-in, super fast renderer.
	*/
	uint32 i;
	uint32 max_pos;
	assert(sal_mem_is_address_valid(origin));
	assert(cell_size);
	assert(cell_size <= MAX_ZOOM);
	assert(buff_size);
	assert(buffer);

	/* We make use of openmp for multi-threaded looping. This allows even
	faster render times, wherever openmp is supported.
	*/
	#pragma omp parallel for
	for (i = 0; i < buff_size; i++) {
		uint32 j;
		uint32 inst_sum = 0;
		uint32 alloc_flag = 0;
		uint32 cell_addr = origin + (i * cell_size);

		for (j = 0; j < cell_size; j++) {
			uint32 address = j + cell_addr;

			if (!sal_mem_is_address_valid(address)) {
				continue;
			}

			inst_sum += sal_mem_get_inst(address);

			if (sal_mem_is_allocated(address)) {
				alloc_flag = ALLOCATED_FLAG;
			}
		}

		buffer[i] = (uint8)(inst_sum / cell_size);
		buffer[i] |= (uint8)(alloc_flag);
	}

	/* We also iterate through all processes and append extra bit flags to the
	rendered image signaling process IP position and memory block limits.
	*/
	max_pos = origin + (cell_size * buff_size);

	#pragma omp parallel for
	for (i = 0; i < sal_proc_get_count(); i++) {
		if (!sal_proc_is_free(i)) {
			Process proc = sal_proc_get_proc(i);
			apply_flag(origin, max_pos, cell_size, proc.ip, IP_FLAG, buffer);
			apply_flag(
				origin, max_pos, cell_size, proc.mb1a, BLOCK_FLAG, buffer
			);

			if (proc.mb2s) {
				apply_flag(
					origin, max_pos, cell_size, proc.mb2a, BLOCK_FLAG, buffer
				);
			}
		}
	}
}