aboutsummaryrefslogtreecommitdiff
path: root/src/pool.c
blob: de79997e3ef134133217ee4a9bf913a2e307320f (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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <atari.h>
#include "screen.h"
// #include "pool.h"
// #include "addrs.h"
#include "memclear.h"

screen_t screens[MAX_SCREENS];
pool_t pools[MAX_POOLS];

void init_pools(void) {
	char p;

	pools[0].screen_count = 0;
	pools[0].free_list = (line_t *)END_MARKER;

	for(p = 1; p < MAX_POOLS; p++)
		pools[p].screen_count = POOL_UNUSED;

	add_to_pool(0, SCR_MAIN_MEM, SCR_MAIN_END);

	if((u16)OS.memlo < SCR_LOW_END - sizeof(pool_t))
		add_to_pool(0, (u16)OS.memlo, SCR_LOW_END);

	/* TODO: for pool 0, add whatever RAM exists between the end
	   of the BSS and $3600. also, under-OS XL RAM if enabled. */

	/* TODO: support pools 1 and up for other banks! */
}

void add_to_pool(char p, u16 start, u16 end) {
	line_t *l;

	end -= sizeof(line_t);

	l = (line_t *)start;

	while(l <= (line_t *)end) {
		memclear(l, sizeof(line_t));
		l->next = pools[p].free_list;
		pools[p].free_list = l;
		l++;
	}
}

char get_smallest_pool(void) {
	char p, r;
	u16 min;

	min = 0xffff;
	r = 0;

	for(p = 0; p < MAX_POOLS; p++) {
		if(pools[p].screen_count = POOL_UNUSED)
			continue; /* maybe break here instead */
		if(pools[p].screen_count < min) {
			min = pools[p].screen_count;
			r = p;
		}
	}
	return r;
}

line_t *steal_line(char s) {
	line_t *l, *last_l;
	char candidate, victim;
	u16 maxheight;

	victim = s;
	maxheight = 0;

	for(candidate = 0; candidate < MAX_SCREENS; candidate++) {
		/* only steal from the same pool */
		if(screens[candidate].pool != screens[s].pool)
			continue;
		/* only steal from screens that exist */
		if(screens[candidate].status == SCR_UNUSED)
			continue;
		/* steal from the screen with the most lines */
		if(screens[candidate].line_count > maxheight) {
			maxheight = screens[candidate].line_count;
			victim = candidate;
		}
	}

	/* find 2nd to last line of the victim screen */
	l = screens[victim].line_list;
	while(l->next != (line_t *)END_MARKER) {
		last_l = l;
		l = l->next;
	}
	/* at the end of the loop, l is the last line before the
	   end marker (the line we're stealing), and last_l is the line
	   before that. */

	/* make old_l the last line */
	last_l->next = (line_t *)END_MARKER;

	/* clear out old screen data, then return the stolen line */
	memclear(l->data, LINE_LEN);

	return l;
}

line_t *find_line(char s) {
	line_t *p;

	p = pools[screens[s].pool].free_list;
	if(p != (line_t *)END_MARKER) {
		pools[screens[s].pool].free_list = p->next;
		return p;
	}

	/* free_list was null, pool is full */
	return steal_line(s);
}

void add_line(char s) {
	line_t *p;

	p = find_line(s);
	p->next = screens[s].line_list;
	screens[s].line_list = p;
	screens[s].line_count++;
}

void pool_reclaim_lines(char s) {
	line_t *p, *q;

	p = screens[s].line_list;
	while(p != (line_t *)END_MARKER) {
		q = p;
		p = p->next;
	}

	q->next = pools[screens[s].pool].free_list;
	pools[screens[s].pool].free_list = screens[s].line_list;

	/* theoretically this could be 0, but as a safety net... */
   screens[s].line_list = (line_t *)END_MARKER;
}