Changes in / [40b2112:7b50125] in buchla-emu
- Files:
-
- 5 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
.gitignore
r40b2112 r7b50125 1 1 bios.abs 2 bios.elf 2 3 midas.abs 4 midas.elf 3 5 4 build 6 build/* 5 7 buchla 8 buchla.exe 6 9 mkdisk 10 mkdisk.exe 7 11 8 12 buchla.disk -
Makefile
r40b2112 r7b50125 4 4 GCC := gcc 5 5 SDL2 := /opt/sdl2 6 EXT := 6 7 else 7 8 GCC := x86_64-w64-mingw32-gcc 8 9 SDL2 := /opt/sdl2-win 10 EXT := .exe 9 11 endif 10 12 … … 32 34 FLAGS_LNK := $(FLAGS) -pthread -Wall -Wextra 33 35 LIBS := $(SDL2_LIB)/libSDL2.a \ 36 $(SDL2_LIB)/libSDL2_net.a \ 34 37 $(SDL2_LIB)/libSDL2_ttf.a \ 35 38 $(SDL2_LIB)/libfreetype.a \ … … 41 44 FLAGS_LNK := $(FLAGS) -Wall -Wextra 42 45 LIBS := $(SDL2_LIB)/libSDL2.a \ 46 $(SDL2_LIB)/libSDL2_net.a \ 43 47 $(SDL2_LIB)/libSDL2_ttf.a \ 44 48 $(SDL2_LIB)/libfreetype.a \ … … 60 64 $(SDL2_LIB)/libSDL2.a \ 61 65 $(SDL2_LIB)/libSDL2main.a \ 66 $(SDL2_LIB)/libSDL2_net.a \ 62 67 $(SDL2_LIB)/libSDL2_ttf.a \ 63 68 $(SDL2_LIB)/libfreetype.a \ 64 69 -l gdi32 \ 65 70 -l imm32 \ 71 -l iphlpapi \ 66 72 -l ole32 \ 67 73 -l oleaut32 \ 68 74 -l version \ 69 -l winmm 75 -l winmm \ 76 -l ws2_32 70 77 endif 71 78 72 79 HEADERS := $(wildcard cpu/*.h) $(wildcard emu/*.h) 73 80 74 all: buchla buchla.disk81 all: buchla$(EXT) buchla.disk 75 82 76 build: 77 mkdir build 78 79 build/gen: | build 83 build/gen: 80 84 gcc $(FLAGS) -o build/gen cpu/m68kmake.c 81 85 … … 90 94 91 95 $(GEN_CP) $(GEN_HP): \ 92 build/gen | build96 build/gen 93 97 cd cpu; ../build/gen ../build 94 98 … … 100 104 CPU_OP := $(CPU_O:%=build/%) 101 105 102 build/%.o: cpu/%.c $(HEADERS) $(GEN_HP) | build106 build/%.o: cpu/%.c $(HEADERS) $(GEN_HP) 103 107 $(GCC) $(FLAGS_CPU) -c -o $@ $< 104 108 105 109 EMU_C := main.c cpu.c vid.c fpu.c tim.c lcd.c ser.c mid.c fdd.c snd.c \ 106 led.c kbd.c sdl.c 110 led.c kbd.c sdl.c gdb.c 107 111 EMU_O := $(EMU_C:.c=.o) 108 112 EMU_OP := $(EMU_O:%=build/%) 109 113 110 build/%.o: emu/%.c $(HEADERS) | build114 build/%.o: emu/%.c $(HEADERS) 111 115 $(GCC) $(FLAGS_EMU) -c -o $@ $< 112 116 113 buchla :$(CPU_OP) $(GEN_OP) $(EMU_OP)114 $(GCC) $(FLAGS_LNK) -o buchla \117 buchla$(EXT): $(CPU_OP) $(GEN_OP) $(EMU_OP) 118 $(GCC) $(FLAGS_LNK) -o buchla$(EXT) \ 115 119 $(CPU_OP) $(GEN_OP) $(EMU_OP) \ 116 120 $(LIBS) 117 121 118 mkdisk :emu/mkdisk.c119 $(GCC) $(FLAGS_AUX) -o mkdisk emu/mkdisk.c122 mkdisk$(EXT): emu/mkdisk.c 123 $(GCC) $(FLAGS_AUX) -o mkdisk$(EXT) emu/mkdisk.c 120 124 121 buchla.disk: mkdisk midas.abs122 ./mkdisk 125 buchla.disk: mkdisk$(EXT) midas.abs 126 ./mkdisk$(EXT) 123 127 124 run: buchla buchla.disk125 ./buchla 128 run: buchla$(EXT) buchla.disk 129 ./buchla$(EXT) ${EMU_OPTS} 126 130 127 val: buchla buchla.disk131 val: buchla$(EXT) buchla.disk 128 132 valgrind --leak-resolution=high --track-fds=yes --leak-check=full \ 129 --show-reachable=yes --suppressions=misc/buchla.supp ./buchla 133 --show-reachable=yes --suppressions=misc/buchla.supp \ 134 ./buchla$(EXT) ${EMU_OPTS} 130 135 131 136 clean: 132 rm - rf build133 rm -f buchla 134 rm -f mkdisk 137 rm -f build/gen build/*.c build/*.h build/*.o 138 rm -f buchla$(EXT) 139 rm -f mkdisk$(EXT) 135 140 rm -f buchla.disk -
emu/all.h
r40b2112 r7b50125 28 28 29 29 #include <SDL2/SDL.h> 30 #include <SDL2/SDL_net.h> 30 31 #include <SDL2/SDL_ttf.h> 31 32 … … 47 48 48 49 extern int32_t sdl_verbose; 50 extern int32_t gdb_verbose; 49 51 extern int32_t cpu_verbose; 50 52 extern int32_t fpu_verbose; … … 61 63 extern const char *bios; 62 64 extern const char *disk; 65 extern const char *font; 66 67 extern SDL_atomic_t run; 63 68 64 69 extern void sdl_init(void); 65 70 extern void sdl_quit(void); 71 extern void sdl_loop(void); 66 72 73 extern void gdb_init(void); 74 extern void gdb_quit(void); 75 extern void gdb_loop(void); 76 extern void gdb_inst(bool bp); 77 78 extern SDL_mutex *cpu_mutex; 79 80 extern void cpu_init(void); 81 extern void cpu_quit(void); 67 82 extern void cpu_loop(void); 83 84 extern uint8_t cpu_peek(int32_t addr); 85 extern void cpu_poke(int32_t addr, uint8_t val); 68 86 69 87 extern void fpu_init(void); … … 97 115 extern void ser_write(uint32_t off, int32_t sz, uint32_t val); 98 116 117 extern void ser_sdl(void); 99 118 extern void ser_text(SDL_TextInputEvent *ev); 100 119 extern void ser_key(SDL_KeyboardEvent *ev); -
emu/cpu.c
r40b2112 r7b50125 52 52 } hw_t; 53 53 54 static uint64_t freq; 55 static uint64_t quan; 56 57 SDL_mutex *cpu_mutex; 58 54 59 static bool reset = true; 55 60 … … 69 74 static hw_t hw_map[] = { 70 75 { 0x180000, 0x200000, 0, fpu_init, fpu_quit, fpu_exec, fpu_read, fpu_write }, 71 { 0x200000, 0x28000 0, 0, vid_init, vid_quit, vid_exec, vid_read, vid_write },76 { 0x200000, 0x280002, 0, vid_init, vid_quit, vid_exec, vid_read, vid_write }, 72 77 { 0x3a0001, 0x3a4001, 4, tim_init, tim_quit, tim_exec, tim_read, tim_write }, 73 78 { 0x3a4001, 0x3a8001, 0, lcd_init, lcd_quit, lcd_exec, lcd_read, lcd_write }, … … 379 384 } 380 385 381 // handle loading midas.abs386 // once midas.abs gets loaded, activate RAM 382 387 383 388 if (addr == APP_START) { 389 ram_data[addr] = (uint8_t)val; 384 390 ram_rw_beg = APP_START; 385 391 ram_rw_end = RAM_START + RAM_SIZE; … … 462 468 } 463 469 470 uint8_t cpu_peek(int32_t addr) 471 { 472 if (addr >= RAM_START && addr <= RAM_START + RAM_SIZE - 1) { 473 return ram_data[addr - RAM_START]; 474 } 475 476 if (addr >= ROM_START && addr <= ROM_START + ROM_SIZE - 1) { 477 return rom_data[addr - ROM_START]; 478 } 479 480 return 0; 481 } 482 483 void cpu_poke(int32_t addr, uint8_t val) 484 { 485 if (addr >= RAM_START && addr <= RAM_START + RAM_SIZE - 1) { 486 ram_data[addr - RAM_START] = val; 487 } 488 489 if (addr >= ROM_START && addr <= ROM_START + ROM_SIZE - 1) { 490 rom_data[addr - ROM_START] = val; 491 } 492 } 493 464 494 static void inst_cb(void) 465 495 { 466 496 uint32_t pc = m68k_get_reg(NULL, M68K_REG_PC); 467 497 uint32_t op = m68k_read_memory_16(pc); 498 499 gdb_inst(op == 0x4e4f); 468 500 469 501 if (op == 0x4e4d) { … … 619 651 } 620 652 621 void cpu_loop(void) 622 { 653 void cpu_init(void) 654 { 655 cpu_mutex = SDL_CreateMutex(); 656 657 if (cpu_mutex == NULL) { 658 fail("SDL_CreateMutex() failed: %s", SDL_GetError()); 659 } 660 661 freq = SDL_GetPerformanceFrequency(); 662 quan = freq / PER_SEC; 663 664 inf("freq %" PRIu64 " quan %" PRIu64, freq, quan); 665 623 666 hw_init(); 624 667 bios_init(); 625 668 626 inf("entering CPU loop");627 669 m68k_init(); 628 670 m68k_set_cpu_type(M68K_CPU_TYPE_68000); 629 671 m68k_set_instr_hook_callback(inst_cb); 630 672 m68k_pulse_reset(); 631 632 uint64_t freq = SDL_GetPerformanceFrequency(); 633 uint64_t quan = freq / PER_SEC; 634 inf("freq %" PRIu64 " quan %" PRIu64, freq, quan); 635 636 bool run = true; 637 638 #if defined EMU_LINUX 639 SDL_Scancode down = SDL_SCANCODE_UNKNOWN; 640 #endif 641 642 while (run) { 673 } 674 675 void cpu_quit(void) 676 { 677 hw_quit(); 678 SDL_DestroyMutex(cpu_mutex); 679 } 680 681 void cpu_loop(void) 682 { 683 inf("entering CPU loop"); 684 int32_t count = 0; 685 686 while (SDL_AtomicGet(&run) != 0) { 643 687 uint64_t until = SDL_GetPerformanceCounter() + quan; 688 689 if (SDL_LockMutex(cpu_mutex) < 0) { 690 fail("SDL_LockMutex() failed: %s", SDL_GetError()); 691 } 644 692 645 693 m68k_execute(CPU_FREQ / PER_SEC); … … 652 700 m68k_set_irq(irq); 653 701 654 SDL_Event ev; 655 656 while (SDL_PollEvent(&ev) > 0) { 657 #if defined EMU_LINUX 658 // Work around duplicate key-down events on Linux. 659 660 if (ev.type == SDL_KEYDOWN) { 661 if (down == ev.key.keysym.scancode) { 662 continue; 663 } 664 665 down = ev.key.keysym.scancode; 702 if (SDL_UnlockMutex(cpu_mutex) < 0) { 703 fail("SDL_UnlockMutex() failed: %s", SDL_GetError()); 704 } 705 706 if ((++count & 0x1ff) == 0) { 707 SDL_Delay(0); 708 } 709 710 while (SDL_GetPerformanceCounter() < until) { 711 for (int32_t i = 0; i < 100; ++i) { 712 _mm_pause(); 666 713 } 667 else if (ev.type == SDL_KEYUP) {668 down = SDL_SCANCODE_UNKNOWN;669 }670 #endif671 672 if (ev.type == SDL_QUIT ||673 (ev.type == SDL_KEYDOWN && ev.key.keysym.sym == SDLK_ESCAPE)) {674 run = false;675 continue;676 }677 678 if (ev.type == SDL_TEXTINPUT) {679 ser_text(&ev.text);680 continue;681 }682 683 if (ev.type == SDL_KEYDOWN) {684 ser_key(&ev.key);685 continue;686 }687 }688 689 while (SDL_GetPerformanceCounter() < until) {690 _mm_pause();691 714 } 692 715 } 693 716 694 717 inf("leaving CPU loop"); 695 hw_quit(); 696 } 718 } -
emu/main.c
r40b2112 r7b50125 25 25 static verb_flag_t verb_flags[] = { 26 26 { "sdl", &sdl_verbose }, 27 { "gdb", &gdb_verbose }, 27 28 { "cpu", &cpu_verbose }, 28 29 { "fpu", &fpu_verbose }, … … 40 41 const char *bios = "bios.abs"; 41 42 const char *disk = "buchla.disk"; 43 const char *font = "ttf/vera-sans-mono.ttf"; 44 45 SDL_atomic_t run; 42 46 43 47 static void usage(FILE *fh) 44 48 { 45 fprintf(fh, "usage: buchla [-h] [-v comp [-v comp [...]]] [-b bios] [-d disk] \n");49 fprintf(fh, "usage: buchla [-h] [-v comp [-v comp [...]]] [-b bios] [-d disk] [-f font]\n"); 46 50 fprintf(fh, "where comp is one of: "); 47 51 … … 83 87 } 84 88 89 if (strcmp(argv[i], "-f") == 0) { 90 if (++i == argc) { 91 usage(stderr); 92 fprintf(stderr, "missing argument to -f\n"); 93 exit(1); 94 } 95 96 font = argv[i]; 97 continue; 98 } 99 85 100 if (strcmp(argv[i], "-v") == 0) { 86 101 if (++i == argc) { … … 118 133 } 119 134 135 static int32_t cpu_thread(void *data) 136 { 137 (void)data; 138 139 cpu_loop(); 140 return 0; 141 } 142 143 static int32_t gdb_thread(void *data) 144 { 145 (void)data; 146 147 gdb_loop(); 148 return 0; 149 } 150 120 151 int32_t main(int32_t argc, char *argv[]) 121 152 { 122 153 parse_args(argc, argv); 123 154 sdl_init(); 155 gdb_init(); 156 cpu_init(); 124 157 125 cpu_loop(); 158 SDL_AtomicSet(&run, 1); 159 SDL_Thread *thr_cpu = SDL_CreateThread(cpu_thread, "cpu", NULL); 126 160 161 if (thr_cpu == NULL) { 162 fail("SDL_CreateThread() failed: %s", SDL_GetError()); 163 } 164 165 SDL_Thread *thr_gdb = SDL_CreateThread(gdb_thread, "gdb", NULL); 166 167 if (thr_gdb == NULL) { 168 fail("SDL_CreateThread() failed: %s", SDL_GetError()); 169 } 170 171 sdl_loop(); 172 173 SDL_WaitThread(thr_cpu, NULL); 174 SDL_WaitThread(thr_gdb, NULL); 175 176 cpu_quit(); 177 gdb_quit(); 127 178 sdl_quit(); 128 179 return 0; -
emu/sdl.c
r40b2112 r7b50125 18 18 #include <all.h> 19 19 20 int32_t sdl_verbose = false;20 int32_t sdl_verbose = 0; 21 21 22 22 #define ver(...) _ver(sdl_verbose, 0, __VA_ARGS__) 23 23 #define ver2(...) _ver(sdl_verbose, 1, __VA_ARGS__) 24 24 #define ver3(...) _ver(sdl_verbose, 2, __VA_ARGS__) 25 26 typedef void (*sdl_func_t)(void); 27 28 static sdl_func_t sdl_funcs[] = { 29 ser_sdl 30 }; 25 31 26 32 void sdl_init(void) … … 32 38 33 39 SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_VERBOSE); 40 41 if (SDLNet_Init() < 0) { 42 fail("SDLNet_Init() failed: %s", SDLNet_GetError()); 43 } 34 44 35 45 if (TTF_Init() < 0) { … … 44 54 { 45 55 TTF_Quit(); 56 SDLNet_Quit(); 46 57 SDL_Quit(); 47 58 } 59 60 void sdl_loop(void) 61 { 62 inf("entering SDL loop"); 63 64 #if defined EMU_LINUX 65 SDL_Scancode down = SDL_SCANCODE_UNKNOWN; 66 #endif 67 68 while (SDL_AtomicGet(&run) != 0) { 69 for (int32_t i = 0; i < ARRAY_COUNT(sdl_funcs); ++i) { 70 sdl_funcs[i](); 71 } 72 73 SDL_Event ev; 74 75 while (SDL_PollEvent(&ev) > 0) { 76 #if defined EMU_LINUX 77 // Work around duplicate key-down events on Linux. 78 79 if (ev.type == SDL_KEYDOWN) { 80 if (down == ev.key.keysym.scancode) { 81 continue; 82 } 83 84 down = ev.key.keysym.scancode; 85 } 86 else if (ev.type == SDL_KEYUP) { 87 down = SDL_SCANCODE_UNKNOWN; 88 } 89 #endif 90 91 if (ev.type == SDL_QUIT || 92 (ev.type == SDL_KEYDOWN && ev.key.keysym.sym == SDLK_ESCAPE)) { 93 ver("quit"); 94 SDL_AtomicSet(&run, 0); 95 continue; 96 } 97 98 if (ev.type == SDL_TEXTINPUT) { 99 ser_text(&ev.text); 100 continue; 101 } 102 103 if (ev.type == SDL_KEYDOWN) { 104 ser_key(&ev.key); 105 continue; 106 } 107 108 SDL_Delay(50); 109 } 110 } 111 112 inf("leaving SDL loop"); 113 } -
emu/ser.c
r40b2112 r7b50125 37 37 #define CON_FGR ((SDL_Color){ .r = 255, .b = 255, .g = 255, .a = 255 }) 38 38 39 #define CON_FONT "ttf/vera-sans-mono.ttf"40 41 39 #define REG_IER_ISR 0 42 40 #define REG_CFR_SR 1 … … 60 58 static SDL_Window *win; 61 59 static SDL_Renderer *ren; 60 static SDL_atomic_t frame; 62 61 63 62 static TTF_Font *fon; … … 70 69 static int32_t bel = 0; 71 70 72 static void update(void) 73 { 71 static void scroll(void) 72 { 73 memmove(mem, mem + 1, (CON_H - 1) * (CON_W + 1)); 74 memset(mem + (CON_H - 1), ' ', CON_W); 75 } 76 77 static void forw(void) 78 { 79 if (cur_x < CON_W - 1) { 80 ++cur_x; 81 return; 82 } 83 84 if (cur_y == CON_H - 1) { 85 cur_x = 0; 86 scroll(); 87 return; 88 } 89 90 cur_x = 0; 91 ++cur_y; 92 } 93 94 static void back(void) 95 { 96 if (cur_x > 0) { 97 --cur_x; 98 return; 99 } 100 101 if (cur_y == 0) { 102 return; 103 } 104 105 cur_x = CON_W - 1; 106 --cur_y; 107 } 108 109 static void down(void) 110 { 111 if (cur_y < CON_H - 1) { 112 ++cur_y; 113 return; 114 } 115 116 scroll(); 117 } 118 119 static void echo(uint8_t c) 120 { 121 if (c < 32) { 122 switch (c) { 123 case '\r': 124 cur_x = 0; 125 break; 126 127 case '\n': 128 down(); 129 break; 130 131 case '\b': 132 back(); 133 break; 134 135 case '\a': 136 bel = BEL_CYC; 137 break; 138 139 default: 140 echo('^'); 141 echo((uint8_t)(c + '@')); 142 return; 143 } 144 } 145 else { 146 mem[cur_y][cur_x] = c; 147 forw(); 148 } 149 150 SDL_AtomicAdd(&frame, 1); 151 } 152 153 static void out(int32_t un, uint8_t c) 154 { 155 if (SDL_LockMutex(cpu_mutex) < 0) { 156 fail("SDL_LockMutex() failed: %s", SDL_GetError()); 157 } 158 159 state[un].rdr = c; 160 state[un].rdr_ok = true; 161 state[un].irq_r = true; 162 163 if (SDL_UnlockMutex(cpu_mutex) < 0) { 164 fail("SDL_UnlockMutex() failed: %s", SDL_GetError()); 165 } 166 } 167 168 void ser_sdl(void) 169 { 170 ver3("ser_sdl()"); 171 172 static int32_t last = 0; 173 int32_t now = SDL_AtomicGet(&frame); 174 175 if (last == now) { 176 ver3("no update"); 177 return; 178 } 179 180 last = now; 181 74 182 if (SDL_FillRect(sur, NULL, bel == 0 ? CON_BGR : CON_BEL) < 0) { 75 183 fail("SDL_FillRect() failed: %s", SDL_GetError()); … … 86 194 87 195 for (int32_t y = 0; y < CON_H; ++y) { 88 SDL_Surface *lin = TTF_RenderText_Blended(fon, (char *)mem[y], CON_FGR); 196 char line[CON_W + 1]; 197 198 if (SDL_LockMutex(cpu_mutex) < 0) { 199 fail("SDL_LockMutex() failed: %s", SDL_GetError()); 200 } 201 202 memcpy(line, mem[y], CON_W + 1); 203 204 if (SDL_UnlockMutex(cpu_mutex) < 0) { 205 fail("SDL_UnlockMutex() failed: %s", SDL_GetError()); 206 } 207 208 SDL_Surface *lin = TTF_RenderText_Blended(fon, line, CON_FGR); 89 209 90 210 if (lin == NULL) { … … 118 238 } 119 239 120 static void scroll(void)121 {122 memmove(mem, mem + 1, (CON_H - 1) * (CON_W + 1));123 memset(mem + (CON_H - 1), ' ', CON_W);124 }125 126 static void forw(void)127 {128 if (cur_x < CON_W - 1) {129 ++cur_x;130 return;131 }132 133 if (cur_y == CON_H - 1) {134 cur_x = 0;135 scroll();136 return;137 }138 139 cur_x = 0;140 ++cur_y;141 }142 143 static void back(void)144 {145 if (cur_x > 0) {146 --cur_x;147 return;148 }149 150 if (cur_y == 0) {151 return;152 }153 154 cur_x = CON_W - 1;155 --cur_y;156 }157 158 static void down(void)159 {160 if (cur_y < CON_H - 1) {161 ++cur_y;162 return;163 }164 165 scroll();166 }167 168 static void echo(uint8_t c)169 {170 if (c < 32) {171 switch (c) {172 case '\r':173 cur_x = 0;174 break;175 176 case '\n':177 down();178 break;179 180 case '\b':181 back();182 break;183 184 case '\a':185 bel = BEL_CYC;186 break;187 188 default:189 echo('^');190 echo((uint8_t)(c + '@'));191 return;192 }193 }194 else {195 mem[cur_y][cur_x] = c;196 forw();197 }198 199 update();200 }201 202 static void out(int32_t un, uint8_t c)203 {204 state[un].rdr = c;205 state[un].rdr_ok = true;206 state[un].irq_r = true;207 }208 209 240 void ser_key(SDL_KeyboardEvent *ev) 210 241 { … … 252 283 } 253 284 254 SDL_RWops *ops = SDL_RWFromFile(CON_FONT, "rb"); 285 SDL_AtomicSet(&frame, 1); 286 287 SDL_RWops *ops = SDL_RWFromFile(font, "rb"); 255 288 256 289 if (ops == NULL) { 257 fail("error while opening font file " CON_FONT ": %s", SDL_GetError());290 fail("error while opening font file %s: %s", font, SDL_GetError()); 258 291 } 259 292 … … 261 294 262 295 if (fon == NULL) { 263 fail("error while loading font file " CON_FONT ": %s", TTF_GetError());296 fail("error while loading font file %s: %s", font, TTF_GetError()); 264 297 } 265 298 … … 286 319 mem[y][CON_W] = 0; 287 320 } 288 289 update();290 321 } 291 322 … … 309 340 310 341 if (bel == BEL_CYC - 1 || bel == 0) { 311 update();342 SDL_AtomicAdd(&frame, 1); 312 343 } 313 344 } -
readme.txt
r40b2112 r7b50125 26 26 https://libsdl.org/ 27 27 28 The SDL2 website also hosts the SDL2_ttf project, which adds support 29 for TrueType fonts to SDL2. SDL2_ttf, in turn, requires the FreeType 30 library, which is available from the FreeType website: 28 The SDL2 website also hosts the SDL2_net and SDL2_ttf projects, which 29 add support for networking and TrueType fonts to SDL2 30 31 SDL2_ttf, in turn, requires the FreeType library, which is available 32 from the FreeType website: 31 33 32 34 https://www.freetype.org/ … … 67 69 make install 68 70 69 # Build and install SDL2_ttf last71 # Build and install SDL2_ttf, now that we have FreeType and SDL2 70 72 71 73 tar zxvf SDL2_ttf-2.0.14.tar.gz … … 76 78 ../configure --prefix=/opt/sdl2 \ 77 79 --with-sdl-prefix=/opt/sdl2 --with-freetype-prefix=/opt/sdl2 80 81 make 82 make install 83 84 # Build and install SDL2_net last 85 86 tar zxvf SDL2_net-2.0.1.tar.gz 87 cd SDL2_net-2.0.1 88 mkdir build 89 cd build 90 91 ../configure --prefix=/opt/sdl2 --with-sdl-prefix=/opt/sdl2 78 92 79 93 make … … 99 113 Then, to cross-build the emulator, invoke 100 114 101 make buchla WIN=1115 make buchla.exe WIN=1 102 116 103 117 from the top-level directory of this repository. Defining the "WIN" … … 105 119 library directory. 106 120 121 In addition to the emulator, we need to build the mkdisk utility, 122 which we'll use to create a 720-KiB floppy disk image that can be read 123 by the Buchla firmware. 124 125 Building mkdisk works pretty much like building the emulator. On Linux 126 and OS X, invoke 127 128 make mkdisk 129 130 from the top-level directory of this repository. To cross-build the 131 Windows version, invoke 132 133 make mkdisk.exe WIN=1 134 135 instead. 136 137 138 Running the emulator 139 -------------------- 140 141 This is where this repository, buchla-emu, meets its companion 142 repository, buchla-68k. We assume that you built the following files 143 according to the instructions in the buchla-68k repository: 144 145 bios.abs 146 midas.abs 147 148 Please copy (or symlink) them into the top-level directory of this 149 repository, buchla-emu. 150 151 bios.abs contains the Buchla 700's BIOS code. The file is loaded by 152 the emulator directly to emulate the BIOS PROM. 153 154 midas.abs is the MIDAS VII software. Unlike the BIOS, which resides in 155 a PROM, it is loaded from a floppy disk. To create this floppy disk, 156 we need the mkdisk utility. 157 158 mkdisk expects to be run from inside the directory that contains 159 midas.abs and produces a disk image file, buchla.disk in the same 160 directory. For example, on Linux: 161 162 ~/buchla-emu$ ls -l midas.abs 163 lrwxrwxrwx 1 emu emu 23 Jul 30 18:07 midas.abs -> ../buchla-68k/midas.abs 164 ~/buchla-emu$ ./mkdisk 165 ~/buchla-emu$ ls -l buchla.disk 166 -rw-r--r-- 1 emu emu 737280 Aug 6 09:44 buchla.disk 167 168 Now we have everything in place to run the emulator. On Linux and OS X 169 you can invoke it directly from the top-level directory of this 170 repository: 171 172 ~/buchla-emu$ ./buchla 173 174 If you prefer to install the emulator elsewhere, be sure to copy the 175 following files: 176 177 buchla | buchla.exe emulator executable (.exe for Windows) 178 ttf/vera-sans-mono.ttf emulator font 179 bios.abs BIOS code 180 buchla.disk disk image 181 182 This also applies to copying the cross-compiled Windows emulator to a 183 Windows machine. 184 185 If you would like to keep the BIOS code, disk image, and font separate 186 from the emulator executable, check out the emulator's -b, -d, and -f 187 command line options. Use -h for an overview of all available options. 188 189 190 Cross-debugging the firmware 191 ---------------------------- 192 193 While the emulator is running, it listens on TCP port 12053 for 194 incoming connections from a GDB cross-debugger. This allows for 195 comfortable source-level debugging of the cross-compiled BIOS and 196 MIDAS VII code, while it runs in the emulator. 197 198 We assume that you have a GCC cross-toolchain in /opt/cross-m68k, as 199 described in the buchla-68k repository. Based on that, we build a 200 GDB cross-debugger: 201 202 # If you haven't yet done so, add the cross-toolchain to your 203 # PATH, so that the GDB build can find it. 204 205 export PATH="/opt/cross-m68k/bin:${PATH}" 206 207 tar zxvf gdb-7.12.tar.gz 208 cd gdb-7.12 209 210 mkdir build 211 cd build 212 213 ../configure --prefix=/opt/cross-m68k --target=m68k-none-elf 214 215 make -j2 216 make install 217 218 The Buchla firmware uses its own (Atari-like) object and executable 219 file format. However, the cross-toolchain and the cross-debugger 220 support the ELF standard. 221 222 When you built the BIOS and MIDAS VII software, you ended up with two 223 files in the Buchla's executable file format, bios.abs and midas.abs. 224 However, the cross-build process also produces matching ELF files, 225 bios.elf and midas.elf, suitable for the cross-debugger. 226 227 Depending on whether you would like to cross-debug the BIOS or MIDAS 228 VII, you'd specify either bios.elf or midas.elf when invoking the 229 cross-debugger. 230 231 To follow along the following example, copy (or symlink) bios.elf and 232 midas.elf from the buchla-68k repository into the top-level directory 233 of this repository. 234 235 In order to open a debug session for the BIOS, run the cross-debugger 236 with bios.abs and connect it to the running emulator using GDB's 237 238 target remote :12053 239 240 command. 12053 is the port on which the emulator listens for incoming 241 GDB connections. 242 243 host:~/buchla-emu$ m68k-none-elf-gdb ./bios.elf 244 GNU gdb (GDB) 7.12 245 Copyright (C) 2016 Free Software Foundation, Inc. 246 [...] 247 (gdb) target remote :12053 248 Remote debugging using :12053 249 trwzsup () at rom/bios.s:832 250 832 move.l 0(a0,d0),d0 | Get routine address 251 (gdb) 252 253 From here on, everything is pretty much standard GDB, for example: 254 255 (gdb) break pscan 256 Breakpoint 1 at 0x105a64: file rom/romp.c, line 3403. 257 (gdb) cont 258 [...] 259 (gdb) bt 260 #0 pscan () at rom/romp.c:3403 261 #1 0x00105e96 in main () at rom/romp.c:3587 262 #2 0x00105fd6 in Croot (cp=0x0) at prolog/croot.c:141 263 #3 0x00105f52 in start1 () at prolog/fsmain.s:59 264 (gdb) 265 266 In order to debug MIDAS VII, run the cross-debugger with midas.elf, 267 instead: 268 269 host:~/buchla-emu$ m68k-none-elf-gdb ./midas.elf 270 GNU gdb (GDB) 7.12 271 Copyright (C) 2016 Free Software Foundation, Inc. 272 [...] 273 107 274 108 275 Emulated hardware … … 118 285 * Motorola MC6840: Timers. 119 286 120 * Motorola MC6850: Serial console and MIDI ports.287 * Rockwell R65C52: Serial console and MIDI ports. 121 288 122 289 * Epson SED1335: LCD controller. … … 166 333 167 334 2. A second chip for the actual sound generation. This is likely 168 a DSP, possibly a Hitachi HD61810, which supports a 16-bit 169 floating-point format that's also found in the firmware 170 source code (12-bit mantissa, 4-bit exponent). 171 172 This chip takes in the current levels of a voice's envelopes 173 and, based on them, performs the FM synthesis for this voice 174 by modulating the user-drawn carrier waves A and B according 175 to the selected FM configuration (algorithm). 335 a DSP. 336 337 XXX - Details to be filled in. 176 338 177 339 We don't know how many of the envelopes not related to FM … … 190 352 would be great to be able to compare the emulation to real hardware. 191 353 192 If it's non-functional, this is also fine. We might be able to gain193 some insights from readingthe FPU microcode PROMs.354 If your Buchla is non-functional, this is also fine. We might be able 355 to gain some insights from reading out the FPU microcode PROMs.
Note:
See TracChangeset
for help on using the changeset viewer.