aboutsummaryrefslogtreecommitdiff
path: root/src/render.c
blob: 66db0c40e2cb1b9af9cdc27764af178e80868124 (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
94
95
96
97
#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_capacity(); 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
				);
			}
		}
	}
}