Форум программистов, компьютерный форум CyberForum.ru

Эмулятор CHIP-8 - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 67, средняя оценка - 4.88
ForEveR
Модератор
Эксперт С++
 Аватар для ForEveR
7933 / 4715 / 318
Регистрация: 24.06.2010
Сообщений: 10,525
Завершенные тесты: 3
10.08.2010, 06:34     Эмулятор CHIP-8 #1
Мы с fasked написали простенький эмулятор для платформы CHIP-8.
CHIP-8
Остались вопросы по графике и клавиатуре. Если кто знает как реализовать - помогите, пожалуйста.
Так же приглашаем для участия в доработке этого проекта, а так же следующих проектах всех, кто желает учиться и трудиться.
Кому интересна работа эмулятора все вопросы к fasked)
Полный проект в прикрепленном архиве в сообщении ниже

CHIP8
types.h
C++
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
/**************************************************************
* TYPES.H                                                     *
* Emulator CHIP-8                                             *
*                                                             *
* basic typedef and constants                                 *
*                                                             *
* LAST UPD: 09/08/2010                                        *
*                                                             *
* by Lavroff and fasked (c)                                   *
**************************************************************/
 
#ifndef HEADER_TYPES_H
#define HEADER_TYPES_H
 
typedef unsigned char  BYTE;
typedef unsigned short WORD;
 
#define DATA_REG_SIZE   16
#define ADDR_REG_SIZE   4096
#define STACK_SIZE      16
 
#define SCREEN_VER_SIZE 32
#define SCREEN_HOR_SIZE 64 
 
#define VIDEO_MEM_SIZE (SCREEN_HOR_SIZE * SCREEN_VER_SIZE)
 
#endif /* HEADER_TYPES_H */


chip-8.h
C++
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
/**************************************************************
* CHIP8.H                                                     *
* Emulator CHIP-8                                             *
*                                                             *
* basic declarations                                          *
*                                                             *
* LAST UPD: 09/08/2010                                        *
*                                                             *
* by Lavroff and fasked (c)                                   *
**************************************************************/
 
#ifndef _HEADER_CHIP8_H_
#define _HEADER_CHIP8_H_
 
#include "types.h"
 
//Declaration of global variables and arrays
static BYTE dataRegisters[DATA_REG_SIZE];
static BYTE addrRegisters[ADDR_REG_SIZE];
 
static WORD stackMemory[STACK_SIZE];
static BYTE videoMemory[VIDEO_MEM_SIZE];
 
static BYTE soundTimer;
static BYTE delayTimer;
 
static WORD iRegister;
 
static BYTE stackCounter;
static WORD offsetMemory;
 
const static BYTE font[80] = { 
   0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
   0x20, 0x60, 0x20, 0x20, 0x70, // 1
   0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
   0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
   0x90, 0x90, 0xF0, 0x10, 0x10, // 4
   0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
   0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
   0xF0, 0x10, 0x20, 0x40, 0x40, // 7
   0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
   0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
   0xF0, 0x90, 0xF0, 0x90, 0x90, // A
   0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
   0xF0, 0x80, 0x80, 0x80, 0xF0, // C
   0xE0, 0x90, 0x90, 0x90, 0xE0, // D
   0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
   0xF0, 0x80, 0xF0, 0x80, 0x80  // F
};
 
//Declaration of macro
#define START_OFFSET 200
 
#define DATA_REG_VX(n)\
   (dataRegisters[(0x0F00 & n) >> 8])
 
#define DATA_REG_VY(n)\
   (dataRegisters[(0x00F0 & n) >> 4])
 
#define DATA_REG_VF\
   (dataRegisters[0xF])
 
#define DATA_REG_V0\
   (dataRegisters[0x0])
 
//Declaration of functions
void InitialiseEmulator();
void EmulatorRun();
 
void LoadOpcodes(WORD * opcodes);
 
WORD GetOpcode();
void ExecuteOpcode (WORD opcode);
 
void ExecuteOpcode0(WORD opcode);
void ExecuteOpcode1(WORD opcode);
void ExecuteOpcode2(WORD opcode);
void ExecuteOpcode3(WORD opcode);
void ExecuteOpcode4(WORD opcode);
void ExecuteOpcode5(WORD opcode);
void ExecuteOpcode6(WORD opcode);
void ExecuteOpcode7(WORD opcode);
void ExecuteOpcode8(WORD opcode);
void ExecuteOpcode9(WORD opcode);
void ExecuteOpcodeA(WORD opcode);
void ExecuteOpcodeB(WORD opcode);
void ExecuteOpcodeC(WORD opcode);
void ExecuteOpcodeD(WORD opcode);
void ExecuteOpcodeE(WORD opcode);
void ExecuteOpcodeF(WORD opcode);
 
void RedrawScreen();
void Delay();
void SoundPlay();
 
#endif /* HEADER_CHIP8_H */


chip8.cpp
C++
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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
#include <iostream>
#include <windows.h>
#include "chip8.h"
 
void RedrawScreen()
{
   system("cls");
   for(int i = 0; i < SCREEN_HOR_SIZE; ++i)
   {
      for(int j = 0; j < SCREEN_VER_SIZE; ++j)
      {
         if(videoMemory[i * SCREEN_HOR_SIZE + j])
            printf("*");
         else
            printf(" ");
      }
 
      printf("\n");
   }
}
 
void Delay()
{
   if(delayTimer)
   {
      Sleep(delayTimer*1000);
   }
}
 
void SoundPlay()
{
   if(soundTimer)
   {
      for(int i=0;i<soundTimer;++i)
         std::cout<<'\a'<<std::endl;
   }
}
 
void InitialiseEmulator()
{
   stackCounter = 0;
   soundTimer = 0;
   delayTimer = 0;
 
   offsetMemory = START_OFFSET;
   iRegister = START_OFFSET;
 
   memset(dataRegisters, 0, DATA_REG_SIZE * sizeof(BYTE));
   memset(addrRegisters, 0, ADDR_REG_SIZE * sizeof(BYTE));
   memset(videoMemory, 0, VIDEO_MEM_SIZE * sizeof(BYTE));
   memset(stackMemory, 0, STACK_SIZE * sizeof(WORD));
   memcpy(addrRegisters, font, 80);
}
 
void LoadOpcodes(WORD * opcodes)
{
   memcpy(addrRegisters + offsetMemory, opcodes, ADDR_REG_SIZE * sizeof(BYTE));
}
 
WORD GetOpcode()
{
   return *(WORD*)(addrRegisters + offsetMemory); // TODO исправить на более правильный вариант
}
 
void EmulatorRun()
{
   WORD opcode = 0;
   for(;;)
   {
      opcode = GetOpcode();
//#ifdef _DEBUG
//      printf("%s: %#0.4x | %s: %#0.4x\n", "OFFSET", offsetMemory, "OPCODE", opcode);
//#endif
 
      if(opcode == 0)
         break;
 
      ExecuteOpcode(opcode);
 
      offsetMemory += 2;
 
      SoundPlay();
      Delay();
      //RedrawScreen();
   }
}
 
void ExecuteOpcode0(WORD opcode)
{
   if((opcode & 0x00FF) == 0xE0)
      memset(videoMemory, 0, VIDEO_MEM_SIZE * sizeof(BYTE)); // 0x00E0: Clear the Screen
   
   else if((opcode & 0x00FF) == 0xEE)
   {
      --stackCounter;
      offsetMemory = stackMemory[stackCounter];
   }
 
   else if((opcode & 0xF000) == 0)
   {
      //TODO 0NNN-Opcode
   }
}
 
void ExecuteOpcode1(WORD opcode)
{
   offsetMemory = opcode & 0x0FFF;
}
 
void ExecuteOpcode2(WORD opcode)
{
   if(stackCounter < 16)
   {
      stackMemory[stackCounter] = offsetMemory;
      ++stackCounter;
   }
 
   offsetMemory = opcode & 0x0FFF;
}
 
void ExecuteOpcode3(WORD opcode)
{
   if(DATA_REG_VX(opcode) == (opcode & 0x00FF))
      offsetMemory += 2;
}
 
void ExecuteOpcode4(WORD opcode)
{
   if(DATA_REG_VX(opcode) != (opcode & 0x00FF))
      offsetMemory += 2;
}
 
void ExecuteOpcode5(WORD opcode)
{
   if(DATA_REG_VX(opcode) == DATA_REG_VY(opcode))
      offsetMemory += 2;
}
 
void ExecuteOpcode6(WORD opcode)
{
   DATA_REG_VX(opcode) = 0x00FF & opcode;
}
 
void ExecuteOpcode7(WORD opcode)
{
   DATA_REG_VX(opcode) += 0x00FF & opcode;
}
 
void ExecuteOpcode8(WORD opcode)
{
   if((opcode & 0xF) == 0x0)
      DATA_REG_VX(opcode) = DATA_REG_VY(opcode);
   
   else if((opcode & 0xF) == 0x1)
      DATA_REG_VX(opcode) |= DATA_REG_VY(opcode);
 
   else if((opcode & 0xF) == 0x2)
      DATA_REG_VX(opcode) &= DATA_REG_VY(opcode);
 
   else if((opcode & 0xF) == 0x3)
      DATA_REG_VX(opcode) ^= DATA_REG_VY(opcode);
 
   else if((opcode & 0xF) == 0x4)
   {
      WORD t = DATA_REG_VX(opcode) + DATA_REG_VY(opcode);
      DATA_REG_VX(opcode) = (BYTE)t;
      DATA_REG_VF = (BYTE)(t & 0x100); 
   }
 
   else if((opcode & 0xF) == 0x5)
   {
      WORD t = DATA_REG_VX(opcode) - DATA_REG_VY(opcode);
      DATA_REG_VX(opcode) = (BYTE)t;
      DATA_REG_VF = (BYTE)((t & 0x100) >> 8);
   }
 
   else if((opcode & 0xF) == 0x6)
   {
      DATA_REG_VF = DATA_REG_VX(opcode) & 1;
      DATA_REG_VX(opcode) >>= 1;
   }
 
   else if((opcode & 0xF) == 0x7)
   {
      WORD t= DATA_REG_VY(opcode)- DATA_REG_VX(opcode);
      DATA_REG_VX(opcode) = (BYTE)t;
      DATA_REG_VF = (BYTE)((t & 0x100) >> 8);
   }
 
   else if((opcode & 0xF) == 0xE)
   {
      DATA_REG_VF = DATA_REG_VX(opcode) & 0x80;
      DATA_REG_VX(opcode) <<= 1;
   }
}
 
void ExecuteOpcode9(WORD opcode)
{
   if(DATA_REG_VX(opcode) != DATA_REG_VY(opcode))
      offsetMemory+=2;  
}
 
void ExecuteOpcodeA(WORD opcode)
{
   iRegister = opcode & 0x0FFF;
}
 
void ExecuteOpcodeB(WORD opcode)
{
   offsetMemory = (opcode & 0x0FFF) + dataRegisters[0];
}
 
void ExecuteOpcodeC(WORD opcode)
{
   DATA_REG_VX(opcode) = (BYTE)(rand()) & (opcode & 0x00FF);
}
 
void ExecuteOpcodeD(WORD opcode)
{
   // TODO D-opcode
   WORD x = DATA_REG_VX(opcode);
   WORD y = DATA_REG_VY(opcode);
   WORD h = opcode & 0x000F;
 
   for(int i = 0; i < h; ++i)
   {
      WORD data = addrRegisters[i + iRegister];
      
      for(int j = 0; j < 8; ++j)
      {
         if((data & (0x80 >> i)) != 0)
         {
            if(videoMemory[j + x + (( y + i ) * SCREEN_HOR_SIZE)] == 1)
               DATA_REG_VF = 1;
            else
               DATA_REG_VF=0;
 
            videoMemory[j + x + (( y + i ) * SCREEN_HOR_SIZE)] ^= 1;
         }
      }
   }
}
 
void ExecuteOpcodeE(WORD opcode)
{
  if((opcode & 0x00FF) == 0x9E)
  {
     // TODO EX9E-Opcode. Keyboard
  }
  else if((opcode & 0x00FF) == 0xA1) 
  {
     // TODO EXA1-Opcode. Keyboard
  }
}
 
void ExecuteOpcodeF(WORD opcode)
{
  if((opcode & 0x000F) == 0x7)
     DATA_REG_VX(opcode) = delayTimer;
 
  else if((opcode & 0x000F) == 0xA)
  {
     //TODO FX0A opcode
  }
  
  else if((opcode & 0x00FF) == 0x15)
     delayTimer = DATA_REG_VX(opcode);
  
  else if((opcode & 0x00FF) == 0x18)
     soundTimer = DATA_REG_VX(opcode);
  
  else if((opcode & 0x00FF) == 0x1E)
     iRegister += DATA_REG_VX(opcode);
  
  else if((opcode & 0x00FF) == 0x29)
  {
     iRegister=DATA_REG_VX(opcode);
  }
  
  else if((opcode & 0x00FF) == 0x33)
  {
     addrRegisters[iRegister] = DATA_REG_VX(opcode) / 100;
     addrRegisters[iRegister + 1] = (DATA_REG_VX(opcode) % 100) / 10;
     addrRegisters[iRegister + 2] = DATA_REG_VX(opcode) % 10;
  }
  
  else if((opcode & 0x00FF) == 0x55)
  {
     for(int i = 0; i < ((opcode & 0x0F00) >> 8); ++i)
        addrRegisters[i + iRegister] = dataRegisters[i];  
  }
  
  else if((opcode & 0x00FF) == 0x65)
  {
     for(int i = 0; i < ((opcode & 0x0F00) >> 8); ++i)
        dataRegisters[i] = addrRegisters[i + iRegister];
  }
} 
 
void ExecuteOpcode(WORD opcode)
{
  WORD opcodeGroup = opcode >> 12; // выделить старшие 4 бита
 
  switch(opcodeGroup)
  {
  case 0x0:
     ExecuteOpcode0(opcode);
     break;
  case 0x1:
     ExecuteOpcode1(opcode);
     break;
  case 0x2:
     ExecuteOpcode2(opcode);
     break;
  case 0x3:
     ExecuteOpcode3(opcode);
     break;
  case 0x4:
     ExecuteOpcode4(opcode);
     break;
  case 0x5:
     ExecuteOpcode5(opcode);
     break;
  case 0x6:
     ExecuteOpcode6(opcode);
     break;
  case 0x7:
     ExecuteOpcode7(opcode);
     break;
  case 0x8:
     ExecuteOpcode8(opcode);
     break;
  case 0x9:
     ExecuteOpcode9(opcode);
     break;
  case 0xA:
     ExecuteOpcodeA(opcode);
     break;
  case 0xB:
     ExecuteOpcodeB(opcode);
     break;
  case 0xC:
     ExecuteOpcodeC(opcode);
     break;
  case 0xD:
     ExecuteOpcodeD(opcode);
     break;
  case 0xE:
     ExecuteOpcodeE(opcode);
     break;
  case 0xF:
     ExecuteOpcodeF(opcode);
     break;
  }
}


main.cpp
C++
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
#include "chip8.h"
 
int main()
{
   // массив опкодов
   // в дальнейшем должны читаться из файлов 
   // специально откомпилированнынх под CHIP-8
   WORD opcodes[ADDR_REG_SIZE] = { 0x6000, 0x6100, 0xA222, 0xC201, 
                                   0x3201, 0xA2E1, 0xD014, 0x7004, 
                                   0x3040, 0x1204, 0x6000, 0x7104, 
                                   0x3120, 0x1204, 0x121C, 0x8040, 
                                   0x2010, 0x2040, 0x8010, 0x0000
   };  
 
   // Инициализация ЦПУ эмулятора
   // очистка памяти, сброс счетчиков и таймеров
   InitialiseEmulator();
 
   // Загрузка опкодов в память эмулятора
   LoadOpcodes(opcodes);
 
   // Запуск эмулятора
   EmulatorRun();
 
   return 0;
}
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
ForEveR
Модератор
Эксперт С++
 Аватар для ForEveR
7933 / 4715 / 318
Регистрация: 24.06.2010
Сообщений: 10,525
Завершенные тесты: 3
13.08.2010, 22:52  [ТС]     Эмулятор CHIP-8 #41
Евгений М., Chip-48 или если проще Super Chip.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Евгений М.
1033 / 974 / 53
Регистрация: 28.02.2010
Сообщений: 2,819
Завершенные тесты: 2
13.08.2010, 22:53     Эмулятор CHIP-8 #42
Понял.
fasked
Эксперт C++
 Аватар для fasked
4925 / 2505 / 180
Регистрация: 07.10.2009
Сообщений: 4,306
Записей в блоге: 1
20.08.2010, 12:32     Эмулятор CHIP-8 #43
У нас был очень большой перерыв

Сейчас появилось небольшое обновление, которое, я надеюсь, все таки поможет отыскать все ошибки в логике работы.

SVN пока что не обновляю, ибо это дополнение не прикручено целиком к коду.
Также расставил по всему коду операторы контроля. Может быть это спасет от таких глупых поисков ошибок, как случилось с опкодом отрисовки спрайта в видеопамять. Ошибка, конечно, так и не была решена, но найти причину того, что программа падала получилось не сразу, а это явный минус.
Миниатюры
Эмулятор CHIP-8  
Евгений М.
1033 / 974 / 53
Регистрация: 28.02.2010
Сообщений: 2,819
Завершенные тесты: 2
20.08.2010, 12:47     Эмулятор CHIP-8 #44
Цитата Сообщение от fasked Посмотреть сообщение
У нас был очень большой перерыв
Я уже успел подумать, что забили на проект.

Ого... Отладчик... Отличная идея.
Насчет интерфейса хотел бы предложите свою идею (См. вложение). Но не в точности как на рисунке (т.к. как реализовать без понятия), а близко. Надо бы еще реализовать брейкпоинты и все такое, что есть в обычном отладчике.

Кстати правильнее писать Debugger (с двумя g).
Миниатюры
Эмулятор CHIP-8  
fasked
Эксперт C++
 Аватар для fasked
4925 / 2505 / 180
Регистрация: 07.10.2009
Сообщений: 4,306
Записей в блоге: 1
20.08.2010, 13:38     Эмулятор CHIP-8 #45
Цитата Сообщение от Евгений М. Посмотреть сообщение
Насчет интерфейса хотел бы предложите свою идею (См. вложение). Но не в точности как на рисунке (т.к. как реализовать без понятия), а близко. Надо бы еще реализовать брейкпоинты и все такое, что есть в обычном отладчике.
Ого, это очень круто. Правда я пока тоже без понятия как можно реализовать, но подумать надо.
Цитата Сообщение от Евгений М. Посмотреть сообщение
Кстати правильнее писать Debugger (с двумя g).
Опять эти глупые опечатки. Спасибо, поправил.

Добавлено через 45 минут
Ну вот уже и первый результат присутствия отладчика появился А ведь прошло совсем ничего.

Немного сейчас упаду в принцип работы самой приставки, чтобы объяснить баг. Для примера взял тот самый проблемный файл с логотипом приставки (Chip8 emulator Logo [Garstyciuks].c8).

Разрешение экрана у приставки 64х32.
Обработка опкода с маской DXYN отвечает за отрисовку спрайта в видеопамять. Координаты спрайта хранятся в регистрах V. Номера регистров берутся из опкода: VX - горизонтальная, VY соответственно вертикальная координата. В младших 4 битах передается высота спрайта. Ширина всегда 8 пикселов.

Соответственно, чтобы отрисовка происходила нормально значения в регистрах не должны превышать разрешение экрана. То есть 0x40 и 0x20. У нас же получалось так, что значения приходили намного большие.

Проблема, как оказалось, крылась в немного неверной обработки опкодов 1NNN (переход по адресу NNN) и 2NNN (вызов процедуры по адресу NNN).
Раньше переход на соответствующий адрес осуществлялся следующим образом:
C
1
PC = (opcode & 0xFFF);
Все просто. Накладываем соответствующую маску на опкод и приравниваем получившееся значение программному счетчику смещения.
Мы не смогли заподозрить очевидного. После каждой обработки опкода счетчик PC увеличивается на два значения и полученный адрес просто напросто пропускался.
В программе "логотипа" по этому адресу как раз находилась операция обнуления регистров VX.
То есть на языке Си этот участок программы можно было бы записать следующим образом:
C
1
2
3
4
5
6
7
8
9
10
11
12
void NullRegisters()
{
   VX = 0;
}
 
void foo()
{
    if(VX >= 0x40) // VX - координата отрисовки спрайта по горизонтали, 0x40 - ширина экрана
        NullRegisters();
    else
        VX += 8;
}
У нас получалось что функция NullRegisters всегда пропускалась

Проблема решилась очень просто. Во всяком случае ассерты контролирующие вылет за пределы видеопамяти у меня больше не вылетают на этой программке.
C
1
PC = (opc & 0xFFF) - 2;
Извините, если много и непонятно написал. Я просто очень рад и хочется поделиться

Очень оригинальное завершение у этой программы
Автор просто сделал вечный цикл. Опкод "прыжка" на адрес переходит на самого же себя.
Евгений М.
1033 / 974 / 53
Регистрация: 28.02.2010
Сообщений: 2,819
Завершенные тесты: 2
20.08.2010, 14:17     Эмулятор CHIP-8 #46
Только что поправил функции ExecuteOpcode1 и ExecuteOpcode2 (ревизия №10). Вот как выглядит наш результат:
Миниатюры
Эмулятор CHIP-8  
fasked
Эксперт C++
 Аватар для fasked
4925 / 2505 / 180
Регистрация: 07.10.2009
Сообщений: 4,306
Записей в блоге: 1
20.08.2010, 14:23     Эмулятор CHIP-8 #47
Цитата Сообщение от Евгений М. Посмотреть сообщение
Только что поправил функции ExecuteOpcode1 и ExecuteOpcode2 (ревизия №10). Вот как выглядит наш результат:
Похоже на правду.
half-node
20.08.2010, 15:15
  #48

Не по теме:

Фига себе...новички...

Alex_Sabaka
 Аватар для Alex_Sabaka
623 / 40 / 9
Регистрация: 28.07.2010
Сообщений: 895
Завершенные тесты: 3
21.08.2010, 11:46     Эмулятор CHIP-8 #49
Есть небольшая идея по поводу проекта. Вы говорили что Вам приходиться опкоды вручную забивать, может стоит написать ассемблер для этих целей.
fasked
Эксперт C++
 Аватар для fasked
4925 / 2505 / 180
Регистрация: 07.10.2009
Сообщений: 4,306
Записей в блоге: 1
21.08.2010, 12:20     Эмулятор CHIP-8 #50
Цитата Сообщение от Alex Sabaka Посмотреть сообщение
Есть небольшая идея по поводу проекта. Вы говорили что Вам приходиться опкоды вручную забивать, может стоит написать ассемблер для этих целей.
Возьметесь?
fasked
Эксперт C++
 Аватар для fasked
4925 / 2505 / 180
Регистрация: 07.10.2009
Сообщений: 4,306
Записей в блоге: 1
21.08.2010, 14:44     Эмулятор CHIP-8 #51
Обновились до 0.0.4dev (Revision 12).

Код интерфейса перевел в соответствующие файлы *.ui. Подумал, что так будет проще вносить изменения в интерфейс. А "рабочий" код легче просматривается, когда не загроможден элементами интерфейса. Это я понял, когда пытался вручную создать форму отладчика

В архив с приложением добавил еще одну программку. Судя по названию это игра про НЛО. Программка также падает при попытке отрисовать спрайты за пределами экрана. Но запускается и заметна какая-то анимация.

Весь код претерпел некоторые изменения. Когда просматривал код в поисках ошибок решил без копипаста переписать некоторые моменты, поэтому названия функций отличаются, расположены по файлам теперь иначе.

Запущенные потоки приостанавливаются при работе. Потому что они занимают ЦП настолько, что основная форма неполностью отрисовывается. И эмулятор иногда от этого падает.

Пара скриншотов прилагается. На первом крестики-нолики, на втором UFO + debugger.

Миниатюры
Эмулятор CHIP-8   Эмулятор CHIP-8  
Alex_Sabaka
 Аватар для Alex_Sabaka
623 / 40 / 9
Регистрация: 28.07.2010
Сообщений: 895
Завершенные тесты: 3
21.08.2010, 17:31     Эмулятор CHIP-8 #52
Цитата Сообщение от fasked Посмотреть сообщение
Возьметесь?
Попробую. Если что-то получиться, то выложу. Но Вы сильно не надейтесь на меня, я не очень крутой программист...
ForEveR
21.08.2010, 19:08  [ТС]
  #53

Не по теме:

fasked, Ты молодец, Саш. Красота!

Евгений М.
1033 / 974 / 53
Регистрация: 28.02.2010
Сообщений: 2,819
Завершенные тесты: 2
21.08.2010, 19:57     Эмулятор CHIP-8 #54
Только что заново прочитал о графике из справочника от Девида Винтера. И нашел то, что не учли:
Graphics are drawn as 8 x 1...15 sprites (they are byte coded). The origin of the screen is the upper left corner. All the coordinates are positive, start at 0, and are calculated modulo 64 for X, and 32 for Y when drawing sprites.
Т.е. к примеру, если спрайт не поместился внизу, то та часть которая не поместилась должна появится сверху.

Предлагаю на 265 и 266 вместо ассертов вставить это:
C
1
2
    x=x%64;
    y=y%64;
А на 279 строке поправить так:
C++
1
int offset = ((i + y)%32) + ((( j + x )%64) * SCREEN_VER_RES);
Alex_Sabaka
 Аватар для Alex_Sabaka
623 / 40 / 9
Регистрация: 28.07.2010
Сообщений: 895
Завершенные тесты: 3
21.08.2010, 19:59     Эмулятор CHIP-8 #55
Уже есть вопрос по поводу ассемблера. Итак, что делают эти инструкции(на вики не очень доходчиво написано, и а англ. у меня не очень):
8XY4 Adds VY to VX. VF is set to 1 when there's a carry, and to 0 when there isn't.
8XY5 VY is subtracted from VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
8XY6 Shifts VX right by one. VF is set to the value of the least significant bit of VX before the shift.
8XY7 Sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
8XYE Shifts VX left by one. VF is set to the value of the most significant bit of VX before the shift.

0NNN Calls RCA 1802 program at address NNN.

ANNN Sets I to the address NNN.

FX07 Sets VX to the value of the delay timer.
FX0A A key press is awaited, and then stored in VX.
FX15 Sets the delay timer to VX.
FX18 Sets the sound timer to VX.
FX1E Adds VX to I. VF is set to 1 when range overflow (I+VX>0xFFF), and 0 when there isn't.
FX29 Sets I to the location of the sprite for the character in VX. Characters 0-F (in hexadecimal) are represented by a 4x5 font.
FX33 Stores the Binary-coded decimal representation of VX at the addresses I, I plus 1, and I plus 2.
FX55 Stores V0 to VX in memory starting at address I.
FX65 Fills V0 to VX with values from memory starting at address I.
fasked
Эксперт C++
 Аватар для fasked
4925 / 2505 / 180
Регистрация: 07.10.2009
Сообщений: 4,306
Записей в блоге: 1
21.08.2010, 20:08     Эмулятор CHIP-8 #56
Цитата Сообщение от Евгений М. Посмотреть сообщение
Т.е. к примеру, если спрайт не поместился внизу, то та часть которая не поместилась должна появится сверху.
Тогда понятно почему срабатывает ассерт, о котором я говорил. Сегодня поправлю, чуть позже.
Цитата Сообщение от Alex Sabaka Посмотреть сообщение
что делают эти инструкции
Чуть позже же выложу объяснения ко всем инструкциям.
Евгений М.
1033 / 974 / 53
Регистрация: 28.02.2010
Сообщений: 2,819
Завершенные тесты: 2
21.08.2010, 20:55     Эмулятор CHIP-8 #57
Теперь насчет обработки опкода FX29.
FX29 I points to the 4 x 5 font sprite of hex char in VX
Т.е. вроде I присваивается адрес спрайта буквы в памяти.

Судя по этому из 339 строки cpu.cpp (ревизия 12):
C++
1
iRegister = REG_VX(opc);
к I просто присваивается значение VX.

Я поправил вот так:
C++
1
iRegister = REG_VX(opc) * 5;
Вроде должны уже цифры рисоваться. Но правильно только единица рисуется. Все остальное нули.
ForEveR
Модератор
Эксперт С++
 Аватар для ForEveR
7933 / 4715 / 318
Регистрация: 24.06.2010
Сообщений: 10,525
Завершенные тесты: 3
21.08.2010, 21:08  [ТС]     Эмулятор CHIP-8 #58
Alex Sabaka,

8XY4 Adds VY to VX. VF is set to 1 when there's a carry, and to 0 when there isn't. - Прибавляем значение регистра Y к значению регистра X. Если переполнение, то есть сумма больше 0xFF - в регистр F записывается 1, иначе 0.
8XY5 VY is subtracted from VX. VF is set to 0 when there's a borrow, and 1 when there isn't. - Вычитаем значение регистра Y из значение регистра X, если разность больше 0xFF - в регистр записывается 1, иначе 0.
8XY6 Shifts VX right by one. VF is set to the value of the least significant bit of VX before the shift. - Сдвигаем значение регистра X вправо на один. VF - наименьший значащий бит регистра X ДО сдвига.
8XY7 Sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't. - Значение регистра X становится равным значение регистра Y минус значение регистра X. Если переполнение VF - один, иначе 0.
8XYE Shifts VX left by one. VF is set to the value of the most significant bit of VX before the shift. - Сдвигаем значение регистра X влево на один. VF - наибольший значащий бит из регистра X ДО сдвига.
0NNN Calls RCA 1802 program at address NNN. - Вызывает какую-то программу. Насколько я понимаю самого процессора или чипа этого компьютера. Вроде как не реализовано.
ANNN Sets I to the address NNN. - I становится равным адресу NNN.
FX07 Sets VX to the value of the delay timer. - Таймер задержки равен значению регистра X.(?)
FX0A A key press is awaited, and then stored in VX. - Ждем нажатия клавиши после чего записываем значение в регистр X.
FX15 Sets the delay timer to VX. - Значение регистра X=значение таймера задержки.
FX18 Sets the sound timer to VX. - Значение регистра X=значение таймера звука.
FX1E Adds VX to I. VF is set to 1 when range overflow (I+VX>0xFFF), and 0 when there isn't. Прибавляем значение регистра X к I. VF - 1 при переполнении, 1+VX>0xFFF, иначе 0.

Далее - затрудняюсь. Да и это не совсем уверен. Что вспомнил - то написал
Tronix
 Аватар для Tronix
157 / 104 / 5
Регистрация: 22.08.2010
Сообщений: 215
22.08.2010, 16:08     Эмулятор CHIP-8 #59
По поводу ассемблера - чем вам CHIPPER от Девида Винтера не угодил? Вполне годная тулза, с исходником.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
22.08.2010, 16:17     Эмулятор CHIP-8
Еще ссылки по теме:

C++ Эмулятор SetTimer
C++ Модифицируйте эмулятор с целью моделирования случайных сбоев ОЗУ
Эмулятор часов настенных (стрелочных) C++
C++ Программа-эмулятор панели Norton Commander
Реализовать эмулятор командной строки C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Евгений М.
1033 / 974 / 53
Регистрация: 28.02.2010
Сообщений: 2,819
Завершенные тесты: 2
22.08.2010, 16:17     Эмулятор CHIP-8 #60
Tronix, так не интересно. Интереснее свою написать.
Yandex
Объявления
22.08.2010, 16:17     Эмулятор CHIP-8
Ответ Создать тему
Опции темы

Текущее время: 23:18. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru