Apply some fixes from Rocinante port

More const on char*s
Remove virtual from MAINboard read and write and just call them directly
Move up regions slightly so they might perform better
This commit is contained in:
Brad Grantham 2020-12-05 17:19:21 -08:00
parent 42109817f2
commit c81a6a8dce
5 changed files with 130 additions and 101 deletions

View File

@ -3,7 +3,8 @@ CXXFLAGS += $(INCFLAGS) -g -Wall --std=c++11 -O2
LDFLAGS += -L/opt/local/lib
LDLIBS += -lglfw -lao -framework OpenGL -framework Cocoa -framework IOkit
OBJECTS = apple2e.o dis6502.o fake6502.o interface.o gl_utility.o
OBJECTS = apple2e.o dis6502.o interface.o gl_utility.o
# fake6502.o
# keyboard.o

View File

@ -14,11 +14,19 @@
#include <functional>
#include <signal.h>
#ifndef M_PI
#define M_PI 3.14159
#endif
// Brad's 6502
#include "cpu6502.h"
#undef SUPPORT_FAKE_6502
// Mike Chambers' 6502
#ifdef SUPPORT_FAKE_6502
#include "fake6502.h"
#endif
using namespace std;
@ -28,14 +36,14 @@ using namespace std;
#define LK_HACK 1
const unsigned int DEBUG_ERROR = 0x01;
const unsigned int DEBUG_WARN = 0x02;
const unsigned int DEBUG_DECODE = 0x04;
const unsigned int DEBUG_STATE = 0x08;
const unsigned int DEBUG_RW = 0x10;
const unsigned int DEBUG_BUS = 0x20;
const unsigned int DEBUG_FLOPPY = 0x40;
const unsigned int DEBUG_SWITCH = 0x80;
constexpr unsigned int DEBUG_ERROR = 0x01;
constexpr unsigned int DEBUG_WARN = 0x02;
constexpr unsigned int DEBUG_DECODE = 0x04;
constexpr unsigned int DEBUG_STATE = 0x08;
constexpr unsigned int DEBUG_RW = 0x10;
constexpr unsigned int DEBUG_BUS = 0x20;
constexpr unsigned int DEBUG_FLOPPY = 0x40;
constexpr unsigned int DEBUG_SWITCH = 0x80;
volatile unsigned int debug = DEBUG_ERROR | DEBUG_WARN ; // | DEBUG_DECODE | DEBUG_STATE | DEBUG_RW;
bool delete_is_left_arrow = true;
@ -74,7 +82,7 @@ struct system_clock
const int machine_clock_rate = 14318180;
bool read_blob(char *name, unsigned char *b, size_t sz)
bool read_blob(const char *name, unsigned char *b, size_t sz)
{
FILE *fp = fopen(name, "rb");
if(fp == NULL) {
@ -124,7 +132,7 @@ static void add_map_entry(char *line)
/**
* Read a map file generated by ld65. Puts symbols into the address_to_function_name map.
*/
static bool read_map(char *name)
static bool read_map(const char *name)
{
char line[100];
FILE *fp = fopen(name, "r");
@ -403,7 +411,7 @@ struct DISKIIboard : board_base
int track_number = 0; // physical track number - DOS and ProDOS only use even tracks
unsigned int track_byte = 0;
void set_floppy(int number, char *name) // number 0 or 1; name = NULL to eject
void set_floppy(int number, const char *name) // number 0 or 1; name = NULL to eject
{
floppy_present[number] = false;
if(name) {
@ -425,7 +433,7 @@ struct DISKIIboard : board_base
typedef std::function<void (int number, bool activity)> floppy_activity_func;
floppy_activity_func floppy_activity;
DISKIIboard(unsigned char diskII_rom[256], char *floppy0_name, char *floppy1_name, floppy_activity_func floppy_activity_) :
DISKIIboard(const unsigned char diskII_rom[256], const char *floppy0_name, const char *floppy1_name, floppy_activity_func floppy_activity_) :
floppy_activity(floppy_activity_)
{
std::copy(diskII_rom, diskII_rom + 0x100, rom_C600.memory.begin());
@ -737,6 +745,20 @@ struct MAINboard : board_base
backed_region ram_6000 = {"ram_6000", 0x6000, 0x6000, RAM, &regions, read_from_main_ram, write_to_main_ram};
backed_region ram_6000_x = {"ram_6000_x", 0x6000, 0x6000, RAM, &regions, read_from_aux_ram, write_to_aux_ram};
bool C08X_read_RAM;
bool C08X_write_RAM;
enum {BANK1, BANK2} C08X_bank;
backed_region rom_D000 = {"rom_D000", 0xD000, 0x1000, ROM, &regions, [&]{return !C08X_read_RAM;}};
backed_region rom_E000 = {"rom_E000", 0xE000, 0x2000, ROM, &regions, [&]{return !C08X_read_RAM;}};
backed_region ram1_main_D000 = {"ram1_main_D000", 0xD000, 0x1000, RAM, &regions, [&]{return !ALTZP && C08X_read_RAM && (C08X_bank == BANK1);}, [&]{return !ALTZP && C08X_write_RAM && (C08X_bank == BANK1);}};
backed_region ram2_main_D000 = {"ram2_main_D000", 0xD000, 0x1000, RAM, &regions, [&]{return !ALTZP && C08X_read_RAM && (C08X_bank == BANK2);}, [&]{return !ALTZP && C08X_write_RAM && (C08X_bank == BANK2);}};
backed_region ram_main_E000 = {"ram1_main_E000", 0xE000, 0x2000, RAM, &regions, [&]{return C08X_read_RAM;}, [&]{return !ALTZP && C08X_write_RAM;}};
backed_region ram1_main_D000_x = {"ram1_main_D000_x", 0xD000, 0x1000, RAM, &regions, [&]{return ALTZP && C08X_read_RAM && (C08X_bank == BANK1);}, [&]{return ALTZP && C08X_write_RAM && (C08X_bank == BANK1);}};
backed_region ram2_main_D000_x = {"ram2_main_D000_x", 0xD000, 0x1000, RAM, &regions, [&]{return ALTZP && C08X_read_RAM && (C08X_bank == BANK2);}, [&]{return ALTZP && C08X_write_RAM && (C08X_bank == BANK2);}};
backed_region ram_main_E000_x = {"ram1_main_E000_x", 0xE000, 0x2000, RAM, &regions, [&]{return ALTZP && C08X_read_RAM;}, [&]{return ALTZP && C08X_write_RAM;}};
enabled_func read_from_aux_text1 = [&]{return (RAMRD && !STORE80) || (STORE80 && PAGE2);};
enabled_func write_to_aux_text1 = [&]{return (RAMWRT && !STORE80) || (STORE80 && PAGE2);};
enabled_func read_from_main_text1 = [&]{return !read_from_aux_text1();};
@ -757,20 +779,6 @@ struct MAINboard : board_base
backed_region hires_page2 = {"hires_page2", 0x4000, 0x2000, RAM, &regions, read_from_main_ram, write_to_main_ram};
backed_region hires_page2x = {"hires_page2x", 0x4000, 0x2000, RAM, &regions, read_from_aux_ram, write_to_aux_ram};
enum {BANK1, BANK2} C08X_bank;
bool C08X_read_RAM;
bool C08X_write_RAM;
backed_region rom_D000 = {"rom_D000", 0xD000, 0x1000, ROM, &regions, [&]{return !C08X_read_RAM;}};
backed_region rom_E000 = {"rom_E000", 0xE000, 0x2000, ROM, &regions, [&]{return !C08X_read_RAM;}};
backed_region ram1_main_D000 = {"ram1_main_D000", 0xD000, 0x1000, RAM, &regions, [&]{return !ALTZP && C08X_read_RAM && (C08X_bank == BANK1);}, [&]{return !ALTZP && C08X_write_RAM && (C08X_bank == BANK1);}};
backed_region ram2_main_D000 = {"ram2_main_D000", 0xD000, 0x1000, RAM, &regions, [&]{return !ALTZP && C08X_read_RAM && (C08X_bank == BANK2);}, [&]{return !ALTZP && C08X_write_RAM && (C08X_bank == BANK2);}};
backed_region ram_main_E000 = {"ram1_main_E000", 0xE000, 0x2000, RAM, &regions, [&]{return C08X_read_RAM;}, [&]{return !ALTZP && C08X_write_RAM;}};
backed_region ram1_main_D000_x = {"ram1_main_D000_x", 0xD000, 0x1000, RAM, &regions, [&]{return ALTZP && C08X_read_RAM && (C08X_bank == BANK1);}, [&]{return ALTZP && C08X_write_RAM && (C08X_bank == BANK1);}};
backed_region ram2_main_D000_x = {"ram2_main_D000_x", 0xD000, 0x1000, RAM, &regions, [&]{return ALTZP && C08X_read_RAM && (C08X_bank == BANK2);}, [&]{return ALTZP && C08X_write_RAM && (C08X_bank == BANK2);}};
backed_region ram_main_E000_x = {"ram1_main_E000_x", 0xE000, 0x2000, RAM, &regions, [&]{return ALTZP && C08X_read_RAM;}, [&]{return ALTZP && C08X_write_RAM;}};
set<int> ignore_mmio = {0xC058, 0xC05A, 0xC05D, 0xC05F, 0xC061, 0xC062};
set<int> banking_read_switches = {
0xC080, 0xC081, 0xC082, 0xC083, 0xC084, 0xC085, 0xC086, 0xC087,
@ -872,7 +880,7 @@ struct MAINboard : board_base
typedef std::function<tuple<float, bool> (int num)> get_paddle_func;
get_paddle_func get_paddle;
clk_t paddles_clock_out[4];
MAINboard(system_clock& clk_, unsigned char rom_image[32768], display_write_func display_write_, audio_flush_func audio_flush_, get_paddle_func get_paddle_) :
MAINboard(system_clock& clk_, const unsigned char rom_image[32768], display_write_func display_write_, audio_flush_func audio_flush_, get_paddle_func get_paddle_) :
clk(clk_),
internal_C800_ROM_selected(true),
speaker_level(waveform[0]),
@ -905,11 +913,11 @@ struct MAINboard : board_base
old_mode_settings = convert_switches_to_mode_settings();
}
virtual ~MAINboard()
~MAINboard()
{
}
virtual void reset()
void reset()
{
// Partially from Apple //e Technical Reference
// XXX need to double-check these against the actual hardware
@ -925,7 +933,7 @@ struct MAINboard : board_base
internal_C800_ROM_selected = true;
}
virtual bool read(int addr, unsigned char &data)
bool read(int addr, unsigned char &data)
{
if(debug & DEBUG_RW) printf("MAIN board read\n");
for(auto b : boards) {
@ -933,6 +941,12 @@ struct MAINboard : board_base
return true;
}
}
for(auto r : regions_by_page[addr / 256]) {
if(r->read(addr, data)) {
if(debug & DEBUG_RW) printf("read 0x%04X -> 0x%02X from %s\n", addr, data, r->name.c_str());
return true;
}
}
if(io_region.contains(addr)) {
if(exit_on_banking && (banking_read_switches.find(addr) != banking_read_switches.end())) {
printf("bank switch control %04X, aborting\n", addr);
@ -1089,12 +1103,6 @@ struct MAINboard : board_base
printf("unhandled MMIO Read at %04X\n", addr);
fflush(stdout); exit(0);
}
for(auto r : regions_by_page[addr / 256]) {
if(r->read(addr, data)) {
if(debug & DEBUG_RW) printf("read 0x%04X -> 0x%02X from %s\n", addr, data, r->name.c_str());
return true;
}
}
if((addr & 0xFF00) == 0xC300) {
if(debug & DEBUG_SWITCH) printf("read 0x%04X, enabling internal C800 ROM\n", addr);
internal_C800_ROM_selected = true;
@ -1114,7 +1122,7 @@ struct MAINboard : board_base
}
return false;
}
virtual bool write(int addr, unsigned char data)
bool write(int addr, unsigned char data)
{
#if LK_HACK
if(addr == 0xBFFE) {
@ -1206,12 +1214,31 @@ struct MAINboard : board_base
#endif
{
display_write(addr, write_to_aux_text1(), data);
if(false && (addr >= 0x2000) && (addr <= 0x3FFF)) {
static FILE* memoryWritesFile = NULL;
if(memoryWritesFile == NULL) {
memoryWritesFile = fopen("memorydump.bin", "wb");
}
unsigned long long c = clk * 1000000 / 14318;
uint16_t a = addr;
uint16_t d = data;
fwrite(&c, sizeof(c), 1, memoryWritesFile);
fwrite(&a, sizeof(a), 1, memoryWritesFile);
fwrite(&d, sizeof(d), 1, memoryWritesFile);
// printf(" { %lld, 0x%04X, 0x%02X }\n", clk * 1000000 / 14318, addr, data);
}
}
for(auto b : boards) {
if(b->write(addr, data)) {
return true;
}
}
for(auto r : regions_by_page[addr / 256]) {
if(r->write(addr, data)) {
if(debug & DEBUG_RW) printf("wrote %02X to 0x%04X in %s\n", addr, data, r->name.c_str());
return true;
}
}
if(io_region.contains(addr)) {
if(exit_on_banking && (banking_write_switches.find(addr) != banking_write_switches.end())) {
printf("bank switch control %04X, exiting\n", addr);
@ -1263,12 +1290,6 @@ struct MAINboard : board_base
printf("unhandled MMIO Write at %04X\n", addr);
fflush(stdout); exit(0);
}
for(auto r : regions_by_page[addr / 256]) {
if(r->write(addr, data)) {
if(debug & DEBUG_RW) printf("wrote %02X to 0x%04X in %s\n", addr, data, r->name.c_str());
return true;
}
}
if(debug & DEBUG_WARN) printf("unhandled memory write to %04X\n", addr);
if(exit_on_memory_fallthrough) {
printf("unhandled memory write to %04X, exiting\n", addr);
@ -1280,7 +1301,7 @@ struct MAINboard : board_base
struct bus_frontend
{
board_base* board;
MAINboard* board;
map<int, vector<unsigned char> > writes;
map<int, vector<unsigned char> > reads;
@ -1315,6 +1336,8 @@ struct bus_frontend
bus_frontend bus;
#ifdef SUPPORT_FAKE_6502
extern "C" {
uint8_t read6502(uint16_t address)
@ -1329,7 +1352,9 @@ void write6502(uint16_t address, uint8_t value)
};
void usage(char *progname)
#endif /* SUPPORT_FAKE_6502 */
void usage(const char *progname)
{
printf("\n");
printf("usage: %s [options] ROM.bin\n", progname);
@ -1354,38 +1379,9 @@ void cleanup(void)
fflush(stderr);
}
#ifdef SUPPORT_FAKE_6502
bool use_fake6502 = false;
struct saved_inst {
int pc;
unsigned char bytes[4];
};
void disassemble_previous_instructions(deque<saved_inst>& previous_instructions)
{
for(auto it : previous_instructions) {
int bytes;
string dis;
tie(bytes, dis) = disassemble_6502(it.pc, it.bytes);
printf("%s\n", dis.c_str());
}
}
const int max_previous_instructions = 100;
void read_instruction_and_save(bus_frontend &bus, int pc, deque<saved_inst>& previous_instructions)
{
saved_inst inst;
inst.pc = pc;
inst.bytes[0] = bus.read(pc + 0);
inst.bytes[1] = bus.read(pc + 1);
inst.bytes[2] = bus.read(pc + 2);
inst.bytes[3] = bus.read(pc + 3);
if(previous_instructions.size() > max_previous_instructions)
previous_instructions.pop_front();
previous_instructions.push_back(inst);
}
#endif
string read_bus_and_disassemble(bus_frontend &bus, int pc)
{
@ -1542,16 +1538,20 @@ enum APPLE2Einterface::EventType process_events(MAINboard *board, bus_frontend&
}
} if(e.type == APPLE2Einterface::RESET) {
bus.reset();
#ifdef SUPPORT_FAKE_6502
if(use_fake6502)
reset6502();
else
#endif
cpu.reset();
} else if(e.type == APPLE2Einterface::REBOOT) {
bus.reset();
board->momentary_open_apple(machine_clock_rate / (5 * 14));
#ifdef SUPPORT_FAKE_6502
if(use_fake6502)
reset6502();
else
#endif
cpu.reset();
} else if(e.type == APPLE2Einterface::PAUSE) {
pause_cpu = e.value;
@ -1602,7 +1602,7 @@ struct averaged_sequence
averaged_sequence() :
where(-1)
{
for(int i = 0; i < LENGTH; i++)
for(unsigned int i = 0; i < LENGTH; i++)
list[i] = 0;
sum = 0;
}
@ -1610,7 +1610,7 @@ struct averaged_sequence
void add(TYPE value)
{
if(where == -1) {
for(int i = 0; i < LENGTH; i++)
for(unsigned int i = 0; i < LENGTH; i++)
list[i] = value;
sum = value * LENGTH;
where = 0;
@ -1630,11 +1630,11 @@ struct averaged_sequence
int main(int argc, char **argv)
{
char *progname = argv[0];
const char *progname = argv[0];
argc -= 1;
argv += 1;
char *diskII_rom_name = NULL, *floppy1_name = NULL, *floppy2_name = NULL;
char *map_name = NULL;
const char *diskII_rom_name = NULL, *floppy1_name = NULL, *floppy2_name = NULL;
const char *map_name = NULL;
bool mute = false;
while((argc > 0) && (argv[0][0] == '-')) {
@ -1699,7 +1699,7 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}
char *romname = argv[0];
const char *romname = argv[0];
unsigned char b[32768];
if(!read_blob(romname, b, sizeof(b)))
@ -1716,8 +1716,6 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}
system_clock clk;
MAINboard* mainboard;
MAINboard::display_write_func display = [](int addr, bool aux, unsigned char data)->bool{return APPLE2Einterface::write(addr, aux, data);};
@ -1762,10 +1760,10 @@ int main(int argc, char **argv)
atexit(cleanup);
#ifdef SUPPORT_FAKE_6502
if(use_fake6502)
reset6502();
deque<saved_inst> previous_instructions;
#endif
APPLE2Einterface::start(run_fast, diskII_rom_name != NULL, floppy1_name != NULL, floppy2_name != NULL);
@ -1796,14 +1794,21 @@ int main(int argc, char **argv)
clk_t prev_clock = clk;
while(clk - prev_clock < clocks_per_slice) {
if(debug & DEBUG_DECODE) {
string dis = read_bus_and_disassemble(bus, use_fake6502 ? pc : cpu.pc);
string dis = read_bus_and_disassemble(bus,
#ifdef SUPPORT_FAKE_6502
use_fake6502 ? pc :
#endif
cpu.pc);
printf("%s\n", dis.c_str());
}
#ifdef SUPPORT_FAKE_6502
if(use_fake6502) {
clockticks6502 = 0;
step6502();
clk.add_cpu_cycles(clockticks6502);
} else {
} else
#endif
{
cpu.cycle();
if(debug & DEBUG_STATE)
print_cpu_state(cpu);
@ -1828,8 +1833,10 @@ int main(int argc, char **argv)
chrono::time_point<chrono::system_clock> now = std::chrono::system_clock::now();
auto elapsed_millis = chrono::duration_cast<chrono::milliseconds>(now - then);
if(!run_fast || pause_cpu)
if(!run_fast || pause_cpu) {
this_thread::sleep_for(chrono::milliseconds(clocks_per_slice * 1000 / machine_clock_rate) - elapsed_millis);
}
then = now;
@ -1873,15 +1880,22 @@ int main(int argc, char **argv)
continue;
}
if(debug & DEBUG_DECODE) {
string dis = read_bus_and_disassemble(bus, use_fake6502 ? pc : cpu.pc);
string dis = read_bus_and_disassemble(bus,
#ifdef SUPPORT_FAKE_6502
use_fake6502 ? pc :
#endif
cpu.pc);
printf("%s\n", dis.c_str());
}
#ifdef SUPPORT_FAKE_6502
if(use_fake6502) {
clockticks6502 = 0;
step6502();
clk.add_cpu_cycles(clockticks6502);
} else {
} else
#endif
{
cpu.cycle();
if(debug & DEBUG_STATE)
print_cpu_state(cpu);
@ -1894,6 +1908,7 @@ int main(int argc, char **argv)
}
APPLE2Einterface::shutdown();
return 0;
}
int hires_visible_address_base[262] =

View File

@ -128,7 +128,7 @@ bool CheckProgramLink(GLuint program)
return false;
}
void opengl_texture::load(int w_, int h_, unsigned char *pixels)
void opengl_texture::load(int w_, int h_, const unsigned char *pixels)
{
w = w_;
h = h_;
@ -137,7 +137,7 @@ void opengl_texture::load(int w_, int h_, unsigned char *pixels)
glBindTexture(GL_TEXTURE_2D, GL_NONE);
}
opengl_texture initialize_texture(int w, int h, unsigned char *pixels)
opengl_texture initialize_texture(int w, int h, const unsigned char *pixels)
{
GLuint tex;

View File

@ -98,10 +98,10 @@ struct opengl_texture
int h;
GLuint t;
operator GLuint() const { return t; }
void load(int w, int h, unsigned char *pixels = NULL);
void load(int w, int h, const unsigned char *pixels = NULL);
};
opengl_texture initialize_texture(int w, int h, unsigned char *pixels = NULL);
opengl_texture initialize_texture(int w, int h, const unsigned char *pixels = NULL);
GLuint GenerateProgram(const std::string& shader_name, const std::string& vertex_shader_text, const std::string& fragment_shader_text);

View File

@ -59,7 +59,7 @@ int joystick_button0 = -1;
int joystick_button1 = -1;
extern int font_offset;
extern unsigned char font_bytes[96 * 7 * 8];
extern const unsigned char font_bytes[96 * 7 * 8];
static int gWindowWidth, gWindowHeight;
@ -184,7 +184,8 @@ static const char *hires_vertex_shader = R"(
raster_coords = vertex_coords;
vec3 screen_coords = to_screen * vec3(vertex_coords + vec2(x_offset, y_offset), 1);
gl_Position = vec4(screen_coords.x, screen_coords.y, .5, 1);
})";
}
)";
static const char *image_fragment_shader = R"(
in vec2 raster_coords;
@ -198,7 +199,8 @@ static const char *image_fragment_shader = R"(
ivec2 tc = ivec2(raster_coords.x, raster_coords.y);
float pixel = texture(image, raster_coords * image_coord_scale).x;
color = vec4(pixel, pixel, pixel, 1);
})";
}
)";
static const char *hires_fragment_shader = R"(
in vec2 raster_coords;
@ -1305,8 +1307,18 @@ static void start_record()
floppy_icon *floppy0_icon;
floppy_icon *floppy1_icon;
uint8_t hgr_page1[8192];
void save_hgr()
{
FILE *fp = fopen("hgr.bin", "wb");
fwrite(hgr_page1, sizeof(hgr_page1), 1, fp);
fclose(fp);
}
void initialize_widgets(bool run_fast, bool add_floppies, bool floppy0_inserted, bool floppy1_inserted)
{
momentary *hgr_momentary = new momentary("SNAP HGR", [](){save_hgr();});
momentary *reset_momentary = new momentary("RESET", [](){event_queue.push_back({RESET, 0});});
momentary *reboot_momentary = new momentary("REBOOT", [](){event_queue.push_back({REBOOT, 0});});
toggle *fast_toggle = new toggle("FAST", run_fast, [](){event_queue.push_back({SPEED, 1});}, [](){event_queue.push_back({SPEED, 0});});
@ -1315,7 +1327,7 @@ void initialize_widgets(bool run_fast, bool add_floppies, bool floppy0_inserted,
toggle *pause_toggle = new toggle("PAUSE", false, [](){event_queue.push_back({PAUSE, 1});}, [](){event_queue.push_back({PAUSE, 0});});
record_toggle = new toggle("RECORD", false, [](){start_record();}, [](){stop_record();});
vector<widget*> controls = {reset_momentary, reboot_momentary, fast_toggle, caps_toggle, color_toggle, pause_toggle, record_toggle};
vector<widget*> controls = {hgr_momentary, reset_momentary, reboot_momentary, fast_toggle, caps_toggle, color_toggle, pause_toggle, record_toggle};
if(false) {
speed_textbox = new textbox("X.YYY MHz");
@ -1890,6 +1902,7 @@ void write2(int addr, bool aux, unsigned char data)
int row = scanout_address / 40;
int col = scanout_address % 40;
glBindTexture(GL_TEXTURE_2D, hires_texture[page]);
if(page == 0) hgr_page1[addr - 0x2000] = data; // XXX hack
unsigned char pixels[8];
for(int i = 0; i < 8 ; i++)
pixels[i] = ((data & (1 << i)) ? 255 : 0);
@ -2000,7 +2013,7 @@ void initialize_memory_to_scanout()
}
int font_offset = 32;
unsigned char font_bytes[96 * 7 * 8] = {
const unsigned char font_bytes[96 * 7 * 8] = {
// 32 :
0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,