-
Notifications
You must be signed in to change notification settings - Fork 0
/
emu.cpp
executable file
·230 lines (193 loc) · 5.82 KB
/
emu.cpp
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <ctime>
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include "dcpu.h"
sf::Color color_table[16] = {
sf::Color::Black,
sf::Color(128, 0, 0), // maroon
sf::Color(0, 128, 0), // dark green
sf::Color(128, 128, 0), // olive
sf::Color(0, 0, 128), // navy blue
sf::Color(128, 0, 128), // purple
sf::Color(0, 128, 128), // teal/cyan
sf::Color(192, 192, 192), // silver
sf::Color(128, 128, 128), // grey
sf::Color::Red,
sf::Color::Green,
sf::Color::Yellow,
sf::Color::Blue,
sf::Color::Magenta,
sf::Color::Cyan,
sf::Color::White
};
string itoa(long i)
{
std::stringstream out;
out << i;
return out.str();
}
bool valid_number_string(char *str)
{
for(int c = 0; str[c]; c++)
if(!isdigit(str[c]))
return false;
return true;
}
void start(void *usr)
{
// CPU thread
Dcpu *cpu = static_cast<Dcpu *> (usr);
cpu->run();
}
void DrawCharacter(sf::Image &screen, unsigned short *font_buff, char c, sf::Color fg_col, sf::Color bg_col, bool blink, int x, int y)
{
/*
set the area on the screen to the proper character c, defined in the font_buf
use the colors fg_col and bg_col
fonts defined in 2 words
upperword aaaa bbbb cccc dddd
lowerword eeee ffff gggg hhhh
character defined as
a a a a
b b b b
c c c c
d d d d
e e e e
f f f f
g g g g
h h h h
1 means set to fg_col, 0 means set to bg col
*/
int font_off_x = x * 4;
int font_off_y = y * 8;
//font_buff += (c * 2); // 1 char per word
unsigned short fontupperword = font_buff[(c * 2)];
unsigned short fontlowerword = font_buff[(c * 2) + 1];
unsigned int font_char = fontupperword << 16 | fontlowerword;
//for(int off = 0; off < 32; off++) // for reverse
for(int off = 31; off >= 0; off--)
{
unsigned int mask = font_char & (1 << (31-off));
int x_img = font_off_x + (off % 4);
int y_img = font_off_y + (off / 4);
if(mask > 0 && !blink)
screen.SetPixel(x_img, y_img, fg_col);
else
screen.SetPixel(x_img, y_img, bg_col);
}
}
int main(int argc, char *argv[])
{
if(argc < 2)
{
cerr << "usage: dcpu <flags> <filename>\n";
return 1;
}
bool debug = false;
int time_to_kill_ms = 0;
// -d runs in debug mode, prints out memory dump at end
for(int a = 1; a < argc - 1; a++)
{
if(!strcmp(argv[a], "-d"))
{
debug = true;
}else
{
cerr << "invalid command <" << argv[a] << ">. ignoring\n";
}
}
ifstream inFile(argv[argc - 1], ios::in);
if(!inFile.good())
{
cerr << "Could not open <" << argv[argc - 1] << ">\n";
return 1;
}
Dcpu cpu(inFile, debug);
sf::Thread cpu_thread(&start, &cpu);
sf::RenderWindow app(sf::VideoMode(TERMINAL_WIDTH * 4 * 4, TERMINAL_HEIGHT * 8 * 4), "DCPPU: DCPU-16 Emulator");
app.SetFramerateLimit(30); // Getting 1500 fps on somthing this simple seems wasteful
sf::Image font;
if(!font.LoadFromFile("font.png"))
{
cerr << "Could not load font\n";
return 1;
}
unsigned short *buf = cpu.GetScreenBuffer();
buf += TERMINAL_WIDTH * TERMINAL_HEIGHT;
// load and encode character set into RAM
for(int char_off = 0; char_off < 128; char_off++)
{
int font_off_x = (char_off * 4) % 128;
int font_off_y = ((char_off * 4) / 128) * 8;
unsigned int font_char = 0;
int x_ = 0;
int y_ = 0;
for(int x = font_off_x; x < font_off_x + 4; x++)
{
for(int y = font_off_y; y < font_off_y + 8; y++)
{
sf::Color pix = font.GetPixel(x, y);
if(pix != sf::Color(2, 1, 2))
font_char |= 1 << (31-((y_ * 4) + x_));
y_++;
}
x_++;
}
unsigned short lowerword = font_char & 0xffff;
unsigned short upperword = (font_char >> 16) & 0xffff;
buf[char_off * 2] = upperword;
buf[char_off * 2 + 1] = lowerword;
}
sf::Image screen;
screen.Create(128, 96); // create black image
screen.SetSmooth(false);
sf::Sprite screen_sprite(screen);
screen_sprite.SetScale(4.0, 4.0);
cpu_thread.Launch();
bool running = true;
while(running)
{
sf::Event Event;
while(app.GetEvent(Event))
{
if(Event.Type == sf::Event::Closed)
{
cpu.kill();
running = false;
app.Close();
}
if (Event.Type == sf::Event::TextEntered)
{
if (Event.Text.Unicode < 128)
{
char c = static_cast<char>(Event.Text.Unicode);
cpu.PushInBuff(c);
}
}
}
app.Clear();
unsigned short *buffer = cpu.GetScreenBuffer();
for(int y = 0; y < TERMINAL_HEIGHT; y++)
{
for(int x = 0; x < TERMINAL_WIDTH; x++)
{
unsigned short sc = buffer[y * 32 + x];
int fg_off = (sc >> 12) & 0xf;
int bg_off = (sc >> 8) & 0xf;
sf::Color fg = color_table[fg_off];
sf::Color bg = color_table[bg_off];
char c = sc & 0x7f;
bool blink = (sc & 0x80) == 0x80 && (time(0) % 2 == 0); // if bit 15 set, blink on for 1 sec, off for 1 sec
DrawCharacter(screen, buffer + (TERMINAL_WIDTH*TERMINAL_HEIGHT), c, fg, bg, blink, x, y);
}
}
app.Draw(screen_sprite);
app.Display();
}
return 0;
}