333 lines
12 KiB
C++
333 lines
12 KiB
C++
#include "zx_ula.h"
|
|
#include <z80.h>
|
|
#include <SDL2/SDL.h>
|
|
|
|
#define AUDIO_BUFFER_SIZE 2048
|
|
|
|
namespace zx_ula
|
|
{
|
|
#define KEY_SHIFT 0
|
|
#define KEY_Z 1
|
|
#define KEY_X 2
|
|
#define KEY_C 3
|
|
#define KEY_V 4
|
|
|
|
#define KEY_A 5
|
|
#define KEY_S 6
|
|
#define KEY_D 7
|
|
#define KEY_F 8
|
|
#define KEY_G 9
|
|
|
|
#define KEY_Q 10
|
|
#define KEY_W 11
|
|
#define KEY_E 12
|
|
#define KEY_R 13
|
|
#define KEY_T 14
|
|
|
|
#define KEY_1 15
|
|
#define KEY_2 16
|
|
#define KEY_3 17
|
|
#define KEY_4 18
|
|
#define KEY_5 19
|
|
|
|
#define KEY_0 20
|
|
#define KEY_9 21
|
|
#define KEY_8 22
|
|
#define KEY_7 23
|
|
#define KEY_6 24
|
|
|
|
#define KEY_P 25
|
|
#define KEY_O 26
|
|
#define KEY_I 27
|
|
#define KEY_U 28
|
|
#define KEY_Y 29
|
|
|
|
#define KEY_RETURN 30
|
|
#define KEY_L 31
|
|
#define KEY_K 32
|
|
#define KEY_J 33
|
|
#define KEY_H 34
|
|
|
|
#define KEY_SPACE 35
|
|
#define KEY_SYMBOL 36
|
|
#define KEY_M 37
|
|
#define KEY_N 38
|
|
#define KEY_B 39
|
|
|
|
uint8_t zx_keyboard[40];
|
|
uint8_t virtual_keyboard[40] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
|
char key_to_keyboard[40] {
|
|
'<','Z','X','C','V',
|
|
'A','S','D','F','G',
|
|
'Q','W','E','R','T',
|
|
'1','2','3','4','5',
|
|
'0','9','8','7','6',
|
|
'P','O','I','U','Y',
|
|
'-','L','K','J','H',
|
|
'.',',','M','N','B'
|
|
};
|
|
static uint8_t border_color = 0;
|
|
static uint8_t ear = 0;
|
|
static uint8_t mic = 0;
|
|
|
|
// this variable keeps track of the last "1" written to the sound buffer, so when streaming it in the audio callback, if there
|
|
// are only zeros remaining in the buffer, we just discard it. It's a poor man's method of keeping the buffer size in control.
|
|
// This is useless when there are music, sounds, tape loading, etc... as 1's and 0's keep alternating
|
|
static uint16_t last_1 = 0;
|
|
|
|
void update_zx_keyboard()
|
|
{
|
|
const uint8_t *keys = SDL_GetKeyboardState(NULL);
|
|
|
|
// Normal keypresses
|
|
zx_keyboard[KEY_SHIFT] = virtual_keyboard[KEY_SHIFT] | keys[SDL_SCANCODE_LSHIFT] | keys[SDL_SCANCODE_RSHIFT];
|
|
zx_keyboard[KEY_Z] = virtual_keyboard[KEY_Z] | keys[SDL_SCANCODE_Z];
|
|
zx_keyboard[KEY_X] = virtual_keyboard[KEY_X] | keys[SDL_SCANCODE_X];
|
|
zx_keyboard[KEY_C] = virtual_keyboard[KEY_C] | keys[SDL_SCANCODE_C];
|
|
zx_keyboard[KEY_V] = virtual_keyboard[KEY_V] | keys[SDL_SCANCODE_V];
|
|
|
|
zx_keyboard[KEY_A] = virtual_keyboard[KEY_A] | keys[SDL_SCANCODE_A];
|
|
zx_keyboard[KEY_S] = virtual_keyboard[KEY_S] | keys[SDL_SCANCODE_S];
|
|
zx_keyboard[KEY_D] = virtual_keyboard[KEY_D] | keys[SDL_SCANCODE_D];
|
|
zx_keyboard[KEY_F] = virtual_keyboard[KEY_F] | keys[SDL_SCANCODE_F];
|
|
zx_keyboard[KEY_G] = virtual_keyboard[KEY_G] | keys[SDL_SCANCODE_G];
|
|
|
|
zx_keyboard[KEY_Q] = virtual_keyboard[KEY_Q] | keys[SDL_SCANCODE_Q];
|
|
zx_keyboard[KEY_W] = virtual_keyboard[KEY_W] | keys[SDL_SCANCODE_W];
|
|
zx_keyboard[KEY_E] = virtual_keyboard[KEY_E] | keys[SDL_SCANCODE_E];
|
|
zx_keyboard[KEY_R] = virtual_keyboard[KEY_R] | keys[SDL_SCANCODE_R];
|
|
zx_keyboard[KEY_T] = virtual_keyboard[KEY_T] | keys[SDL_SCANCODE_T];
|
|
|
|
zx_keyboard[KEY_1] = virtual_keyboard[KEY_1] | keys[SDL_SCANCODE_1] | keys[SDL_SCANCODE_KP_1];
|
|
zx_keyboard[KEY_2] = virtual_keyboard[KEY_2] | keys[SDL_SCANCODE_2] | keys[SDL_SCANCODE_KP_2];
|
|
zx_keyboard[KEY_3] = virtual_keyboard[KEY_3] | keys[SDL_SCANCODE_3] | keys[SDL_SCANCODE_KP_3];
|
|
zx_keyboard[KEY_4] = virtual_keyboard[KEY_4] | keys[SDL_SCANCODE_4] | keys[SDL_SCANCODE_KP_4];
|
|
zx_keyboard[KEY_5] = virtual_keyboard[KEY_5] | keys[SDL_SCANCODE_5] | keys[SDL_SCANCODE_KP_5];
|
|
|
|
zx_keyboard[KEY_0] = virtual_keyboard[KEY_0] | keys[SDL_SCANCODE_0] | keys[SDL_SCANCODE_KP_0];
|
|
zx_keyboard[KEY_9] = virtual_keyboard[KEY_9] | keys[SDL_SCANCODE_9] | keys[SDL_SCANCODE_KP_9];
|
|
zx_keyboard[KEY_8] = virtual_keyboard[KEY_8] | keys[SDL_SCANCODE_8] | keys[SDL_SCANCODE_KP_8];
|
|
zx_keyboard[KEY_7] = virtual_keyboard[KEY_7] | keys[SDL_SCANCODE_7] | keys[SDL_SCANCODE_KP_7];
|
|
zx_keyboard[KEY_6] = virtual_keyboard[KEY_6] | keys[SDL_SCANCODE_6] | keys[SDL_SCANCODE_KP_6];
|
|
|
|
zx_keyboard[KEY_P] = virtual_keyboard[KEY_P] | keys[SDL_SCANCODE_P];
|
|
zx_keyboard[KEY_O] = virtual_keyboard[KEY_O] | keys[SDL_SCANCODE_O];
|
|
zx_keyboard[KEY_I] = virtual_keyboard[KEY_I] | keys[SDL_SCANCODE_I];
|
|
zx_keyboard[KEY_U] = virtual_keyboard[KEY_U] | keys[SDL_SCANCODE_U];
|
|
zx_keyboard[KEY_Y] = virtual_keyboard[KEY_Y] | keys[SDL_SCANCODE_Y];
|
|
|
|
zx_keyboard[KEY_RETURN] = virtual_keyboard[KEY_RETURN] | keys[SDL_SCANCODE_KP_ENTER] | keys[SDL_SCANCODE_RETURN];
|
|
zx_keyboard[KEY_L] = virtual_keyboard[KEY_L] | keys[SDL_SCANCODE_L];
|
|
zx_keyboard[KEY_K] = virtual_keyboard[KEY_K] | keys[SDL_SCANCODE_K];
|
|
zx_keyboard[KEY_J] = virtual_keyboard[KEY_J] | keys[SDL_SCANCODE_J];
|
|
zx_keyboard[KEY_H] = virtual_keyboard[KEY_H] | keys[SDL_SCANCODE_H];
|
|
|
|
zx_keyboard[KEY_SPACE] = virtual_keyboard[KEY_SPACE] | keys[SDL_SCANCODE_SPACE];
|
|
zx_keyboard[KEY_SYMBOL] = virtual_keyboard[KEY_SYMBOL] | keys[SDL_SCANCODE_LCTRL] | keys[SDL_SCANCODE_RCTRL];
|
|
zx_keyboard[KEY_M] = virtual_keyboard[KEY_M] | keys[SDL_SCANCODE_M];
|
|
zx_keyboard[KEY_N] = virtual_keyboard[KEY_N] | keys[SDL_SCANCODE_N];
|
|
zx_keyboard[KEY_B] = virtual_keyboard[KEY_B] | keys[SDL_SCANCODE_B];
|
|
|
|
// Keys in a normal keyboard that ara combinations in the zx one
|
|
if (keys[SDL_SCANCODE_BACKSPACE]) zx_keyboard[KEY_SHIFT] = zx_keyboard[KEY_0] = 1;
|
|
if (keys[SDL_SCANCODE_PERIOD]) zx_keyboard[KEY_SYMBOL] = zx_keyboard[KEY_M] = 1;
|
|
}
|
|
|
|
int port_in(int port)
|
|
{
|
|
const uint8_t h_addr = (port>>8);
|
|
uint8_t result = ear ? 0xff : 0xbf;
|
|
|
|
update_zx_keyboard();
|
|
|
|
if (!(h_addr & ~0xfe))
|
|
{
|
|
result &= ~(
|
|
zx_keyboard[KEY_SHIFT]*0x01 +
|
|
zx_keyboard[KEY_Z]*0x02 +
|
|
zx_keyboard[KEY_X]*0x04 +
|
|
zx_keyboard[KEY_C]*0x08 +
|
|
zx_keyboard[KEY_V]*0x10 );
|
|
}
|
|
if (!(h_addr & ~0xfd))
|
|
{
|
|
result &= ~(
|
|
zx_keyboard[KEY_A]*0x01 +
|
|
zx_keyboard[KEY_S]*0x02 +
|
|
zx_keyboard[KEY_D]*0x04 +
|
|
zx_keyboard[KEY_F]*0x08 +
|
|
zx_keyboard[KEY_G]*0x10 );
|
|
}
|
|
if (!(h_addr & ~0xfb))
|
|
{
|
|
result &= ~(
|
|
zx_keyboard[KEY_Q]*0x01 +
|
|
zx_keyboard[KEY_W]*0x02 +
|
|
zx_keyboard[KEY_E]*0x04 +
|
|
zx_keyboard[KEY_R]*0x08 +
|
|
zx_keyboard[KEY_T]*0x10 );
|
|
}
|
|
if (!(h_addr & ~0xf7))
|
|
{
|
|
result &= ~(
|
|
zx_keyboard[KEY_1]*0x01 +
|
|
zx_keyboard[KEY_2]*0x02 +
|
|
zx_keyboard[KEY_3]*0x04 +
|
|
zx_keyboard[KEY_4]*0x08 +
|
|
zx_keyboard[KEY_5]*0x10 );
|
|
}
|
|
if (!(h_addr & ~0xef))
|
|
{
|
|
result &= ~(
|
|
zx_keyboard[KEY_0]*0x01 +
|
|
zx_keyboard[KEY_9]*0x02 +
|
|
zx_keyboard[KEY_8]*0x04 +
|
|
zx_keyboard[KEY_7]*0x08 +
|
|
zx_keyboard[KEY_6]*0x10 );
|
|
}
|
|
if (!(h_addr & ~0xdf))
|
|
{
|
|
result &= ~(
|
|
zx_keyboard[KEY_P]*0x01 +
|
|
zx_keyboard[KEY_O]*0x02 +
|
|
zx_keyboard[KEY_I]*0x04 +
|
|
zx_keyboard[KEY_U]*0x08 +
|
|
zx_keyboard[KEY_Y]*0x10 );
|
|
}
|
|
if (!(h_addr & ~0xbf))
|
|
{
|
|
result &= ~(
|
|
zx_keyboard[KEY_RETURN]*0x01 +
|
|
zx_keyboard[KEY_L]*0x02 +
|
|
zx_keyboard[KEY_K]*0x04 +
|
|
zx_keyboard[KEY_J]*0x08 +
|
|
zx_keyboard[KEY_H]*0x10 );
|
|
}
|
|
if (!(h_addr & ~0x7f))
|
|
{
|
|
result &= ~(
|
|
zx_keyboard[KEY_SPACE]*0x01 +
|
|
zx_keyboard[KEY_SYMBOL]*0x02 +
|
|
zx_keyboard[KEY_M]*0x04 +
|
|
zx_keyboard[KEY_N]*0x08 +
|
|
zx_keyboard[KEY_B]*0x10 );
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void port_out(int port, int val)
|
|
{
|
|
border_color = val & 0x7;
|
|
mic = (val&0x08)?0:1;
|
|
ear = val&0x10?1:0;
|
|
//printf("EAR:%i MIC:%i\n", ear, mic);
|
|
}
|
|
|
|
uint8_t get_border_color() { return border_color; }
|
|
uint8_t get_ear() { return ear; }
|
|
void set_ear(const uint8_t val) { ear = val; }
|
|
|
|
|
|
|
|
|
|
SDL_AudioDeviceID sdlAudioDevice;
|
|
uint8_t sound_buffer[AUDIO_BUFFER_SIZE];
|
|
uint16_t sound_pos=0;
|
|
uint16_t sound_start=0;
|
|
uint16_t t_sound=0;
|
|
uint32_t samples_generated=0;
|
|
uint32_t samples_time =0;
|
|
uint32_t samples_t=0;
|
|
|
|
void audioCallback(void * userdata, uint8_t * stream, int len)
|
|
{
|
|
//const uint16_t top = sound_pos < len ? sound_pos : len;
|
|
//if (top<len) printf("top: %i, len: %i, pos: %i\n", top, len, sound_pos);
|
|
//memcpy(stream, sound_buffer, top);
|
|
for (int i=0;i<len;++i)
|
|
{
|
|
stream[i] = sound_buffer[(sound_start++)&(AUDIO_BUFFER_SIZE-1)];
|
|
}
|
|
//if (top<len) memchr(&stream[top], sound_buffer[top-1], len-top);
|
|
/*if (top<sound_pos)
|
|
{
|
|
if (last_1>top)
|
|
{
|
|
memcpy(sound_buffer, &sound_buffer[top], sound_pos-top);
|
|
sound_pos=sound_pos-top;
|
|
last_1=last_1-top;
|
|
}
|
|
else
|
|
{
|
|
sound_pos=last_1=0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sound_pos=last_1=0;
|
|
}*/
|
|
}
|
|
|
|
void sound_init()
|
|
{
|
|
SDL_AudioSpec audioSpec{11025, AUDIO_U8, 1, 0, AUDIO_BUFFER_SIZE>>2, 0, 0, &audioCallback, NULL};
|
|
sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0);
|
|
sound_enable();
|
|
samples_time=SDL_GetTicks();
|
|
}
|
|
|
|
void sound_enable()
|
|
{
|
|
SDL_PauseAudioDevice(sdlAudioDevice, 0);
|
|
}
|
|
|
|
void sound_disable()
|
|
{
|
|
SDL_PauseAudioDevice(sdlAudioDevice, 1);
|
|
}
|
|
|
|
void sound_update(const uint8_t dt)
|
|
{
|
|
t_sound += dt;
|
|
samples_t += dt;
|
|
if (t_sound>=317) {
|
|
t_sound-=317;
|
|
samples_generated++;
|
|
if (samples_t >=z80::getClock()) {
|
|
//printf("%i\n", samples_generated);
|
|
samples_generated=0;
|
|
samples_t = 0;
|
|
}
|
|
/*if (SDL_GetTicks()>=samples_time+1000) {
|
|
printf("%i\n", samples_generated);
|
|
samples_generated=0;
|
|
samples_time = SDL_GetTicks();
|
|
}*/
|
|
//sound_pos = (sound_pos+1) & 0x3ff;
|
|
//sound_buffer[sound_pos] = ear*128;
|
|
|
|
//if (sound_pos>=AUDIO_BUFFER_SIZE) sound_pos = last_1 = 0;
|
|
|
|
sound_buffer[(sound_pos++)&(AUDIO_BUFFER_SIZE-1)] = ear*128;
|
|
//if (ear) last_1 = sound_pos;
|
|
}
|
|
}
|
|
|
|
const int getKey(const char key)
|
|
{
|
|
for (int i=0; i<40; ++i) if (key_to_keyboard[i] == key) return i;
|
|
return 0;
|
|
}
|
|
|
|
void keydown(const char key)
|
|
{
|
|
virtual_keyboard[getKey(key)] = 1;
|
|
}
|
|
|
|
void keyup(const char key)
|
|
{
|
|
virtual_keyboard[getKey(key)] = 0;
|
|
}
|
|
|
|
|
|
} |