Compare commits
13 commits
b62d3c6e72
...
c265fb4e1e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c265fb4e1e | ||
| f868c8669f | |||
| 431e905354 | |||
| ce55830a1b | |||
| 47b254f58e | |||
| 697c8859c6 | |||
| f8274158d4 | |||
| 7b8b26f0e0 | |||
| bc6529ea4b | |||
| e2a74064a0 | |||
| 4dea595da2 | |||
| 0be2290d4a | |||
| c5ac98dffb |
10 changed files with 495 additions and 224 deletions
10
Makefile
10
Makefile
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
DEBUG ?= 0
|
||||
MEMSIZE ?= 128
|
||||
ENABLE_AUDIO ?= 1
|
||||
|
||||
SOURCES = $(wildcard src/*.c)
|
||||
|
||||
|
|
@ -54,9 +55,12 @@ endif
|
|||
# Basic support for changing screen res (with the MacPlusV3 ROM)
|
||||
DISP_WIDTH ?= 512
|
||||
DISP_HEIGHT ?= 342
|
||||
CFLAGS_CFG = -DDISP_WIDTH=$(DISP_WIDTH) -DDISP_HEIGHT=$(DISP_HEIGHT)
|
||||
CFLAGS_CFG = -DDISP_WIDTH=$(DISP_WIDTH) -DDISP_HEIGHT=$(DISP_HEIGHT) -DENABLE_AUDIO=$(ENABLE_AUDIO)
|
||||
|
||||
all: main
|
||||
all: main patcher
|
||||
|
||||
patcher: src/rom.c
|
||||
$(CC) $(CFLAGS) -DUMAC_STANDALONE_PATCHER -o $@ $<
|
||||
|
||||
$(MUSASHI_SRC): $(MUSASHI)/m68kops.h
|
||||
|
||||
|
|
@ -74,7 +78,7 @@ main: $(OBJS)
|
|||
|
||||
clean:
|
||||
make -C $(MUSASHI) clean
|
||||
rm -f $(MY_OBJS) main
|
||||
rm -f $(MY_OBJS) main patcher
|
||||
|
||||
################################################################################
|
||||
# Mac driver sources (no need to generally rebuild
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ extern int overlay;
|
|||
* But, that should never happen post-boot.
|
||||
*/
|
||||
#define CLAMP_RAM_ADDR(x) ((x) >= RAM_SIZE ? (x) % RAM_SIZE : (x))
|
||||
/* Is the address (previously clamped with CLAMP_RAM_ADDR) the audio trap address? (last byte of audio data) */
|
||||
#define IS_RAM_AUDIO_TRAP(x) (x == umac_get_audio_offset() + 2 * 369)
|
||||
|
||||
#define IS_VIA(x) ((ADR24(x) & 0xe80000) == 0xe80000)
|
||||
#define IS_IWM(x) ((ADR24(x) >= 0xdfe1ff) && (ADR24(x) < (0xdfe1ff + 0x2000)))
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ void scc_write(unsigned int address, uint8_t data);
|
|||
uint8_t scc_read(unsigned int address);
|
||||
/* Set a new state for the DCD pins: */
|
||||
void scc_set_dcd(int a, int b);
|
||||
/* check if scc master interrupt is enabled */
|
||||
int scc_get_mie();
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ int umac_loop(void);
|
|||
void umac_reset(void);
|
||||
void umac_opt_disassemble(int enable);
|
||||
void umac_mouse(int deltax, int deltay, int button);
|
||||
void umac_absmouse(int x, int y, int button);
|
||||
void umac_kbd_event(uint8_t scancode, int down);
|
||||
|
||||
static inline void umac_vsync_event(void)
|
||||
|
|
@ -53,4 +54,15 @@ static inline unsigned int umac_get_fb_offset(void)
|
|||
return RAM_SIZE - ((DISP_WIDTH * DISP_HEIGHT / 8) + 0x380);
|
||||
}
|
||||
|
||||
#if ENABLE_AUDIO
|
||||
#define umac_get_audio_offset() (RAM_SIZE - 768)
|
||||
#define umac_get_audio_offset_end() (RAM_SIZE - 768 + 2 * 370)
|
||||
extern unsigned first_audio_sample;
|
||||
#define umac_get_first_audio_sample() (first_audio_sample)
|
||||
#define umac_reset_first_audio_sample() (first_audio_sample = 0, (void)0)
|
||||
|
||||
void umac_audio_trap();
|
||||
void umac_audio_cfg(int volume, int sndres);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ struct via_cb {
|
|||
void via_init(struct via_cb *cb);
|
||||
void via_write(unsigned int address, uint8_t data);
|
||||
uint8_t via_read(unsigned int address);
|
||||
void via_tick(uint64_t time);
|
||||
void via_tick(int cycles);
|
||||
int via_limit_cycles(int cycles);
|
||||
/* Trigger an event on CA1 or CA2: */
|
||||
void via_caX_event(int ca);
|
||||
void via_sr_rx(uint8_t val);
|
||||
|
|
|
|||
156
src/main.c
156
src/main.c
|
|
@ -40,6 +40,7 @@
|
|||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "umac.h"
|
||||
#include "machw.h"
|
||||
#include "m68k.h"
|
||||
#include "via.h"
|
||||
|
|
@ -70,8 +71,11 @@ static unsigned int g_int_controller_highest_int = 0; /* Highest pending interr
|
|||
uint8_t *_ram_base;
|
||||
uint8_t *_rom_base;
|
||||
|
||||
#if ENABLE_AUDIO
|
||||
static int umac_volume, umac_sndres;
|
||||
#endif
|
||||
int overlay = 1;
|
||||
static uint64_t global_time_us = 0;
|
||||
static uint64_t global_time_us = 0, global_cycles = 0;
|
||||
static int sim_done = 0;
|
||||
static jmp_buf main_loop_jb;
|
||||
|
||||
|
|
@ -154,8 +158,14 @@ static void via_ra_changed(uint8_t val)
|
|||
MDBG("OVERLAY CHANGING\n");
|
||||
update_overlay_layout();
|
||||
}
|
||||
|
||||
#if ENABLE_AUDIO
|
||||
uint8_t vol = val & 7;
|
||||
if (vol != umac_volume) {
|
||||
umac_volume = val & 7;
|
||||
umac_audio_cfg(umac_volume, umac_sndres);
|
||||
}
|
||||
oldval = val;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void via_rb_changed(uint8_t val)
|
||||
|
|
@ -166,7 +176,13 @@ static void via_rb_changed(uint8_t val)
|
|||
// 4 = mouse4 (in, mouse X2)
|
||||
// 3 = mouse7 (in, 0 = button pressed)
|
||||
// [2:0] = RTC controls
|
||||
(void)val;
|
||||
#if ENABLE_AUDIO
|
||||
uint8_t sndres = val >> 7;
|
||||
if(sndres != umac_sndres) {
|
||||
umac_sndres = sndres;
|
||||
umac_audio_cfg(umac_volume, umac_sndres);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8_t via_ra_in(void)
|
||||
|
|
@ -437,7 +453,13 @@ unsigned int cpu_read_long_dasm(unsigned int address)
|
|||
void FAST_FUNC(cpu_write_byte)(unsigned int address, unsigned int value)
|
||||
{
|
||||
if (IS_RAM(address)) {
|
||||
RAM_WR8(CLAMP_RAM_ADDR(address), value);
|
||||
address = CLAMP_RAM_ADDR(address);
|
||||
RAM_WR8(address, value);
|
||||
#if ENABLE_AUDIO
|
||||
if(IS_RAM_AUDIO_TRAP(address)) {
|
||||
umac_audio_trap();
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -592,10 +614,35 @@ void umac_opt_disassemble(int enable)
|
|||
disassemble = enable;
|
||||
}
|
||||
|
||||
#define MOUSE_MAX_PENDING_PIX 30
|
||||
/* Provide mouse input (movement, button) data.
|
||||
*
|
||||
* X is positive going right; Y is positive going upwards.
|
||||
*/
|
||||
void umac_absmouse(int x, int y, int button)
|
||||
{
|
||||
if (!scc_get_mie()) return;
|
||||
#define MTemp_h 0x82a
|
||||
#define MTemp_v 0x828
|
||||
#define CrsrNew 0x8ce
|
||||
#define CrsrCouple 0x8cf
|
||||
|
||||
static int pending_mouse_deltax = 0;
|
||||
static int pending_mouse_deltay = 0;
|
||||
int oldx = RAM_RD16(MTemp_h);
|
||||
int oldy = RAM_RD16(MTemp_v);
|
||||
|
||||
if(x != oldx) {
|
||||
RAM_WR16(MTemp_h, x);
|
||||
}
|
||||
|
||||
if (y != oldy) {
|
||||
RAM_WR16(MTemp_v, y);
|
||||
}
|
||||
|
||||
if(x != oldx || y != oldy) {
|
||||
RAM_WR8(CrsrNew, RAM_RD8(CrsrCouple));
|
||||
}
|
||||
|
||||
via_mouse_pressed = button;
|
||||
}
|
||||
|
||||
/* Provide mouse input (movement, button) data.
|
||||
*
|
||||
|
|
@ -603,83 +650,22 @@ static int pending_mouse_deltay = 0;
|
|||
*/
|
||||
void umac_mouse(int deltax, int deltay, int button)
|
||||
{
|
||||
pending_mouse_deltax += deltax;
|
||||
pending_mouse_deltay += deltay;
|
||||
|
||||
/* Clamp if the UI has flooded with lots and lots of steps!
|
||||
*/
|
||||
if (pending_mouse_deltax > MOUSE_MAX_PENDING_PIX)
|
||||
pending_mouse_deltax = MOUSE_MAX_PENDING_PIX;
|
||||
if (pending_mouse_deltax < -MOUSE_MAX_PENDING_PIX)
|
||||
pending_mouse_deltax = -MOUSE_MAX_PENDING_PIX;
|
||||
if (pending_mouse_deltay > MOUSE_MAX_PENDING_PIX)
|
||||
pending_mouse_deltay = MOUSE_MAX_PENDING_PIX;
|
||||
if (pending_mouse_deltay < -MOUSE_MAX_PENDING_PIX)
|
||||
pending_mouse_deltay = -MOUSE_MAX_PENDING_PIX;
|
||||
|
||||
/* FIXME: The movement might take a little time, but this
|
||||
* posts the button status immediately. Probably OK, but the
|
||||
* mismatch might be perceptible.
|
||||
*/
|
||||
via_mouse_pressed = button;
|
||||
}
|
||||
|
||||
static void mouse_tick(void)
|
||||
{
|
||||
/* Periodically, check if the mouse X/Y deltas are non-zero.
|
||||
* If a movement is required, encode one step in X and/or Y
|
||||
* and deduct from the pending delta.
|
||||
*
|
||||
* The step ultimately posts an SCC IRQ, so we _don't_ try to
|
||||
* make any more steps while an IRQ is currently pending.
|
||||
* (Currently, that means a previous step's DCD IRQ event
|
||||
* hasn't yet been consumed by the OS handler. In future, if
|
||||
* SCC is extended with other IRQ types, then just checking
|
||||
* the IRQ status is technically too crude, but should still
|
||||
* be fine given the timeframes.)
|
||||
*/
|
||||
if (pending_mouse_deltax == 0 && pending_mouse_deltay == 0)
|
||||
return;
|
||||
|
||||
if (scc_irq_state == 1)
|
||||
return;
|
||||
|
||||
static int old_dcd_a = 0;
|
||||
static int old_dcd_b = 0;
|
||||
|
||||
/* Mouse X/Y quadrature signals are wired to:
|
||||
* VIA Port B[4] & SCC DCD_A for X
|
||||
* VIA Port B[5] & SCC DCD_B for Y
|
||||
*
|
||||
* As VIA mouse signals aren't sampled until IRQ, can do this
|
||||
* in one step, toggling existing DCD states and setting VIA
|
||||
* either equal or opposite to DCD:
|
||||
*/
|
||||
int dcd_a = old_dcd_a;
|
||||
int dcd_b = old_dcd_b;
|
||||
int deltax = pending_mouse_deltax;
|
||||
int deltay = pending_mouse_deltay;
|
||||
uint8_t qb = via_quadbits;
|
||||
|
||||
if (deltax) {
|
||||
dcd_a = !dcd_a;
|
||||
qb = (qb & ~0x10) | ((deltax < 0) == dcd_a ? 0x10 : 0);
|
||||
pending_mouse_deltax += (deltax > 0) ? -1 : 1;
|
||||
MDBG(" px %d, oldpx %d", pending_mouse_deltax, deltax);
|
||||
if (!scc_get_mie()) return;
|
||||
if(deltax) {
|
||||
int16_t temp_h = RAM_RD16(MTemp_h) + deltax;
|
||||
RAM_WR16(MTemp_h, temp_h);
|
||||
}
|
||||
|
||||
if (deltay) {
|
||||
dcd_b = !dcd_b;
|
||||
qb = (qb & ~0x20) | ((deltay < 0) == dcd_b ? 0x20 : 0);
|
||||
pending_mouse_deltay += (deltay > 0) ? -1 : 1;
|
||||
MDBG(" py %d, oldpy %d", pending_mouse_deltay, deltay);
|
||||
int16_t temp_v = RAM_RD16(MTemp_v) - deltay;
|
||||
RAM_WR16(MTemp_v, temp_v);
|
||||
}
|
||||
MDBG("\n");
|
||||
|
||||
via_quadbits = qb;
|
||||
old_dcd_a = dcd_a;
|
||||
old_dcd_b = dcd_b;
|
||||
scc_set_dcd(dcd_a, dcd_b);
|
||||
if(deltax || deltay) {
|
||||
RAM_WR8(CrsrNew, RAM_RD8(CrsrCouple));
|
||||
}
|
||||
|
||||
via_mouse_pressed = button;
|
||||
}
|
||||
|
||||
void umac_reset(void)
|
||||
|
|
@ -705,13 +691,15 @@ int umac_loop(void)
|
|||
{
|
||||
setjmp(main_loop_jb);
|
||||
|
||||
const int us = UMAC_EXECLOOP_QUANTUM;
|
||||
m68k_execute(us*8);
|
||||
global_time_us += us;
|
||||
int cycles = UMAC_EXECLOOP_QUANTUM * 8;
|
||||
cycles = via_limit_cycles(cycles);
|
||||
int used_cycles = m68k_execute(cycles);
|
||||
MDBG("Asked to execute %d cycles, actual %d cycles\n", cycles, used_cycles);
|
||||
global_cycles += used_cycles;
|
||||
global_time_us = global_cycles / 8;
|
||||
|
||||
// Device polling
|
||||
via_tick(global_time_us);
|
||||
mouse_tick();
|
||||
via_tick(used_cycles);
|
||||
kbd_check_work();
|
||||
|
||||
return sim_done;
|
||||
|
|
|
|||
352
src/rom.c
352
src/rom.c
|
|
@ -80,7 +80,7 @@ static uint32_t rom_get_version(uint8_t *rom_base)
|
|||
} while (0)
|
||||
|
||||
|
||||
static void rom_patch_plusv3(uint8_t *rom_base)
|
||||
static int rom_patch_plusv3(uint8_t *rom_base, int disp_width, int disp_height, int ram_size)
|
||||
{
|
||||
/* Inspired by patches in BasiliskII!
|
||||
*/
|
||||
|
|
@ -100,138 +100,143 @@ static void rom_patch_plusv3(uint8_t *rom_base)
|
|||
* - No IWM init
|
||||
* - new Sound?
|
||||
*/
|
||||
#if UMAC_MEMSIZE > 128 && UMAC_MEMSIZE < 512
|
||||
/* Hack to change memtop: try out a 256K Mac :) */
|
||||
for (int i = 0x376; i < 0x37e; i += 2)
|
||||
ROM_WR16(i, M68K_INST_NOP);
|
||||
ROM_WR16(0x376, 0x2a7c); // moveal #RAM_SIZE, A5
|
||||
ROM_WR16(0x378, RAM_SIZE >> 16);
|
||||
ROM_WR16(0x37a, RAM_SIZE & 0xffff);
|
||||
/* That overrides the probed memory size, but
|
||||
* P_ChecksumRomAndTestMemory returns a failure code for
|
||||
* things that aren't 128/512. Skip that:
|
||||
*/
|
||||
ROM_WR16(0x132, 0x6000); // Bra (was BEQ)
|
||||
/* FIXME: We should also remove the memory probe routine, by
|
||||
* allowing the ROM checksum to fail (it returns failure, then
|
||||
* we carry on). This avoids wild RAM addrs being accessed.
|
||||
*/
|
||||
#endif
|
||||
if (ram_size > 128*1024 && ram_size < 512*1024) {
|
||||
/* Hack to change memtop: try out a 256K Mac :) */
|
||||
for (int i = 0x376; i < 0x37e; i += 2)
|
||||
ROM_WR16(i, M68K_INST_NOP);
|
||||
ROM_WR16(0x376, 0x2a7c); // moveal #ram_size, A5
|
||||
ROM_WR16(0x378, ram_size >> 16);
|
||||
ROM_WR16(0x37a, ram_size & 0xffff);
|
||||
/* That overrides the probed memory size, but
|
||||
* P_ChecksumRomAndTestMemory returns a failure code for
|
||||
* things that aren't 128/512. Skip that:
|
||||
*/
|
||||
ROM_WR16(0x132, 0x6000); // Bra (was BEQ)
|
||||
/* FIXME: We should also remove the memory probe routine, by
|
||||
* allowing the ROM checksum to fail (it returns failure, then
|
||||
* we carry on). This avoids wild RAM addrs being accessed.
|
||||
*/
|
||||
|
||||
#if DISP_WIDTH != 512 || DISP_HEIGHT != 342
|
||||
#define SCREEN_SIZE (DISP_WIDTH*DISP_HEIGHT/8)
|
||||
#define SCREEN_DISTANCE_FROM_TOP (SCREEN_SIZE + 0x380)
|
||||
#if (SCREEN_DISTANCE_FROM_TOP >= 65536)
|
||||
#error "rom.c: Screen res patching maths won't work for a screen this large"
|
||||
#endif
|
||||
#define SCREEN_BASE (0x400000-SCREEN_DISTANCE_FROM_TOP)
|
||||
#define SCREEN_BASE_L16 (SCREEN_BASE & 0xffff)
|
||||
#define SBCOORD(x, y) (SCREEN_BASE + ((DISP_WIDTH/8)*(y)) + ((x)/8))
|
||||
/* Fix up the sound buffer as used by BootBeep */
|
||||
ROM_WR32(0x292, ram_size - 768);
|
||||
}
|
||||
|
||||
/* Changing video res:
|
||||
*
|
||||
* Original 512*342 framebuffer is 0x5580 bytes; the screen
|
||||
* buffer lands underneath sound/other buffers at top of mem,
|
||||
* i,e, 0x3fa700 = 0x400000-0x5580-0x380. So any new buffer
|
||||
* will be placed (and read out from for the GUI) at
|
||||
* MEM_TOP-0x380-SCREEN_SIZE.
|
||||
*
|
||||
* For VGA, size is 0x9600 bytes (0x2580 words)
|
||||
*/
|
||||
if(disp_width != 512 || disp_height != 342) {
|
||||
int screen_size = (disp_width*disp_height/8);
|
||||
int screen_distance_from_top = screen_size + 0x380;
|
||||
if (screen_distance_from_top >= 65536) {
|
||||
RERR("rom.c: screen res patching maths won't work for a screen this large");
|
||||
return -1;
|
||||
}
|
||||
int screen_base = 0x400000-screen_distance_from_top;
|
||||
int screen_base_l16 = screen_base & 0xffff;
|
||||
#define SBCOORD(x, y) (screen_base + ((disp_width/8)*(y)) + ((x)/8))
|
||||
|
||||
/* We need some space, low down, to create jump-out-and-patch
|
||||
* routines where a patch is too large to put inline. The
|
||||
* TestSoftware check at 0x42 isn't used:
|
||||
*/
|
||||
ROM_WR16(0x42, 0x6000); /* bra */
|
||||
ROM_WR16(0x44, 0x62-0x44); /* offset */
|
||||
/* Now 0x46-0x57 can be used */
|
||||
unsigned int patch_0 = 0x46;
|
||||
ROM_WR16(patch_0 + 0, 0x9bfc); /* suba.l #imm32, A5 */
|
||||
ROM_WR16(patch_0 + 2, 0); /* (Could add more here) */
|
||||
ROM_WR16(patch_0 + 4, SCREEN_DISTANCE_FROM_TOP);
|
||||
ROM_WR16(patch_0 + 6, 0x6000); /* bra */
|
||||
ROM_WR16(patch_0 + 8, 0x3a4 - (patch_0 + 8)); /* Return to 3a4 */
|
||||
/* Changing video res:
|
||||
*
|
||||
* Original 512*342 framebuffer is 0x5580 bytes; the screen
|
||||
* buffer lands underneath sound/other buffers at top of mem,
|
||||
* i,e, 0x3fa700 = 0x400000-0x5580-0x380. So any new buffer
|
||||
* will be placed (and read out from for the GUI) at
|
||||
* MEM_TOP-0x380-screen_size.
|
||||
*
|
||||
* For VGA, size is 0x9600 bytes (0x2580 words)
|
||||
*/
|
||||
|
||||
/* Magic screen-related locations in Mac Plus ROM 4d1f8172:
|
||||
*
|
||||
* 8c : screen base addr (usually 3fa700, now 3f6680)
|
||||
* 148 : screen base addr again
|
||||
* 164 : u32 screen address of crash Mac/critErr hex numbers
|
||||
* 188 : u16 bytes per row (critErr)
|
||||
* 194 : u16 bytes per row (critErr)
|
||||
* 19c : u16 (bytes per row * 6)-1 (critErr)
|
||||
* 1a4 : u32 screen address of critErr twiddly pattern
|
||||
* 1ee : u16 screen sie in words minus one
|
||||
* 3a2 : u16 screen size in bytes (BUT can't patch immediate)
|
||||
* 474 : u16 bytes per row
|
||||
* 494 : u16 screen y
|
||||
* 498 : u16 screen x
|
||||
* a0e : y
|
||||
* a10 : x
|
||||
* ee2 : u16 bytes per row minus 4 (tPutIcon)
|
||||
* ef2 : u16 bytes per row (tPutIcon)
|
||||
* 7e0 : u32 screen address of disk icon (240, 145)
|
||||
* 7f2 : u32 screen address of disk icon's symbol (248, 160)
|
||||
* f0c : u32 screen address of Mac icon (240, 145)
|
||||
* f18 : u32 screen address of Mac icon's face (248, 151)
|
||||
* f36 : u16 bytes per row minus 2 (mPutSymbol)
|
||||
* 1cd1 : hidecursor's bytes per line
|
||||
* 1d48 : xres minus 32 (for cursor rect clipping)
|
||||
* 1d4e : xres minus 32
|
||||
* 1d74 : y
|
||||
* 1d93 : bytes per line (showcursor)
|
||||
* 1e68 : y
|
||||
* 1e6e : x
|
||||
* 1e82 : y
|
||||
*/
|
||||
ROM_WR16(0x8c, SCREEN_BASE_L16);
|
||||
ROM_WR16(0x148, SCREEN_BASE_L16);
|
||||
ROM_WR32(0x164, SBCOORD(DISP_WIDTH/2 - (48/2), DISP_HEIGHT/2 + 8));
|
||||
ROM_WR16(0x188, DISP_WIDTH/8);
|
||||
ROM_WR16(0x194, DISP_WIDTH/8);
|
||||
ROM_WR16(0x19c, (6*DISP_WIDTH/8)-1);
|
||||
ROM_WR32(0x1a4, SBCOORD(DISP_WIDTH/2 - 8, DISP_HEIGHT/2 + 8 + 8));
|
||||
ROM_WR16(0x1ee, (SCREEN_SIZE/4)-1);
|
||||
/* We need some space, low down, to create jump-out-and-patch
|
||||
* routines where a patch is too large to put inline. The
|
||||
* TestSoftware check at 0x42 isn't used:
|
||||
*/
|
||||
ROM_WR16(0x42, 0x6000); /* bra */
|
||||
ROM_WR16(0x44, 0x62-0x44); /* offset */
|
||||
/* Now 0x46-0x57 can be used */
|
||||
unsigned int patch_0 = 0x46;
|
||||
ROM_WR16(patch_0 + 0, 0x9bfc); /* suba.l #imm32, A5 */
|
||||
ROM_WR16(patch_0 + 2, 0); /* (Could add more here) */
|
||||
ROM_WR16(patch_0 + 4, screen_distance_from_top);
|
||||
ROM_WR16(patch_0 + 6, 0x6000); /* bra */
|
||||
ROM_WR16(patch_0 + 8, 0x3a4 - (patch_0 + 8)); /* Return to 3a4 */
|
||||
|
||||
ROM_WR32(0xf0c, SBCOORD(DISP_WIDTH/2 - 16, DISP_HEIGHT/2 - 26));
|
||||
ROM_WR32(0xf18, SBCOORD(DISP_WIDTH/2 - 8, DISP_HEIGHT/2 - 20));
|
||||
ROM_WR32(0x7e0, SBCOORD(DISP_WIDTH/2 - 16, DISP_HEIGHT/2 - 26));
|
||||
ROM_WR32(0x7f2, SBCOORD(DISP_WIDTH/2 - 8, DISP_HEIGHT/2 - 11));
|
||||
/* Magic screen-related locations in Mac Plus ROM 4d1f8172:
|
||||
*
|
||||
* 8c : screen base addr (usually 3fa700, now 3f6680)
|
||||
* 148 : screen base addr again
|
||||
* 164 : u32 screen address of crash Mac/critErr hex numbers
|
||||
* 188 : u16 bytes per row (critErr)
|
||||
* 194 : u16 bytes per row (critErr)
|
||||
* 19c : u16 (bytes per row * 6)-1 (critErr)
|
||||
* 1a4 : u32 screen address of critErr twiddly pattern
|
||||
* 1ee : u16 screen sie in words minus one
|
||||
* 3a2 : u16 screen size in bytes (BUT can't patch immediate)
|
||||
* 474 : u16 bytes per row
|
||||
* 494 : u16 screen y
|
||||
* 498 : u16 screen x
|
||||
* a0e : y
|
||||
* a10 : x
|
||||
* ee2 : u16 bytes per row minus 4 (tPutIcon)
|
||||
* ef2 : u16 bytes per row (tPutIcon)
|
||||
* 7e0 : u32 screen address of disk icon (240, 145)
|
||||
* 7f2 : u32 screen address of disk icon's symbol (248, 160)
|
||||
* f0c : u32 screen address of Mac icon (240, 145)
|
||||
* f18 : u32 screen address of Mac icon's face (248, 151)
|
||||
* f36 : u16 bytes per row minus 2 (mPutSymbol)
|
||||
* 1cd1 : hidecursor's bytes per line
|
||||
* 1d48 : xres minus 32 (for cursor rect clipping)
|
||||
* 1d4e : xres minus 32
|
||||
* 1d74 : y
|
||||
* 1d93 : bytes per line (showcursor)
|
||||
* 1e68 : y
|
||||
* 1e6e : x
|
||||
* 1e82 : y
|
||||
*/
|
||||
ROM_WR16(0x8c, screen_base_l16);
|
||||
ROM_WR16(0x148, screen_base_l16);
|
||||
ROM_WR32(0x164, SBCOORD(disp_width/2 - (48/2), disp_height/2 + 8));
|
||||
ROM_WR16(0x188, disp_width/8);
|
||||
ROM_WR16(0x194, disp_width/8);
|
||||
ROM_WR16(0x19c, (6*disp_width/8)-1);
|
||||
ROM_WR32(0x1a4, SBCOORD(disp_width/2 - 8, disp_height/2 + 8 + 8));
|
||||
ROM_WR16(0x1ee, (screen_size/4)-1);
|
||||
|
||||
/* Patch "SubA #$5900, A5" to subtract 0x9880.
|
||||
* However... can't just patch the int16 immediate, as that's
|
||||
* sign-extended (and we end up with a subtract-negative,
|
||||
* i.e. an add). There isn't space here to turn it into sub.l
|
||||
* so add some rigamarole to branch to some bytes stolen at
|
||||
* patch_0 up above.
|
||||
*/
|
||||
ROM_WR16(0x3a0, 0x6000); /* bra */
|
||||
ROM_WR16(0x3a2, patch_0 - 0x3a2); /* ...to patch0, returns at 0x3a4 */
|
||||
ROM_WR32(0xf0c, SBCOORD(disp_width/2 - 16, disp_height/2 - 26));
|
||||
ROM_WR32(0xf18, SBCOORD(disp_width/2 - 8, disp_height/2 - 20));
|
||||
ROM_WR32(0x7e0, SBCOORD(disp_width/2 - 16, disp_height/2 - 26));
|
||||
ROM_WR32(0x7f2, SBCOORD(disp_width/2 - 8, disp_height/2 - 11));
|
||||
|
||||
ROM_WR16(0x474, DISP_WIDTH/8);
|
||||
ROM_WR16(0x494, DISP_HEIGHT);
|
||||
ROM_WR16(0x498, DISP_WIDTH);
|
||||
ROM_WR16(0xa0e, DISP_HEIGHT); /* copybits? */
|
||||
ROM_WR16(0xa10, DISP_WIDTH);
|
||||
ROM_WR16(0xee2, (DISP_WIDTH/8)-4); /* tPutIcon bytes per row, minus 4 */
|
||||
ROM_WR16(0xef2, DISP_WIDTH/8); /* tPutIcon bytes per row */
|
||||
ROM_WR16(0xf36, (DISP_WIDTH/8)-2); /* tPutIcon bytes per row, minus 2 */
|
||||
ROM_WR8(0x1cd1, DISP_WIDTH/8); /* hidecursor */
|
||||
ROM_WR16(0x1d48, DISP_WIDTH-32); /* 1d46+2 was originally 512-32 rite? */
|
||||
ROM_WR16(0x1d4e, DISP_WIDTH-32); /* 1d4c+2 is 480, same */
|
||||
ROM_WR16(0x1d6e, DISP_HEIGHT-16); /* showcursor (YESS fixed Y crash bug!) */
|
||||
ROM_WR16(0x1d74, DISP_HEIGHT); /* showcursor */
|
||||
ROM_WR8(0x1d93, DISP_WIDTH/8); /* showcursor */
|
||||
ROM_WR16(0x1e68, DISP_HEIGHT); /* mScrnSize */
|
||||
ROM_WR16(0x1e6e, DISP_WIDTH); /* mScrnSize */
|
||||
ROM_WR16(0x1e82, DISP_HEIGHT); /* tScrnBitMap */
|
||||
/* Patch "SubA #$5900, A5" to subtract 0x9880.
|
||||
* However... can't just patch the int16 immediate, as that's
|
||||
* sign-extended (and we end up with a subtract-negative,
|
||||
* i.e. an add). There isn't space here to turn it into sub.l
|
||||
* so add some rigamarole to branch to some bytes stolen at
|
||||
* patch_0 up above.
|
||||
*/
|
||||
ROM_WR16(0x3a0, 0x6000); /* bra */
|
||||
ROM_WR16(0x3a2, patch_0 - 0x3a2); /* ...to patch0, returns at 0x3a4 */
|
||||
|
||||
ROM_WR16(0x474, disp_width/8);
|
||||
ROM_WR16(0x494, disp_height);
|
||||
ROM_WR16(0x498, disp_width);
|
||||
ROM_WR16(0xa0e, disp_height); /* copybits? */
|
||||
ROM_WR16(0xa10, disp_width);
|
||||
ROM_WR16(0xee2, (disp_width/8)-4); /* tPutIcon bytes per row, minus 4 */
|
||||
ROM_WR16(0xef2, disp_width/8); /* tPutIcon bytes per row */
|
||||
ROM_WR16(0xf36, (disp_width/8)-2); /* tPutIcon bytes per row, minus 2 */
|
||||
ROM_WR8(0x1cd1, disp_width/8); /* hidecursor */
|
||||
ROM_WR16(0x1d48, disp_width-32); /* 1d46+2 was originally 512-32 rite? */
|
||||
ROM_WR16(0x1d4e, disp_width-32); /* 1d4c+2 is 480, same */
|
||||
ROM_WR16(0x1d6e, disp_height-16); /* showcursor (YESS fixed Y crash bug!) */
|
||||
ROM_WR16(0x1d74, disp_height); /* showcursor */
|
||||
ROM_WR8(0x1d93, disp_width/8); /* showcursor */
|
||||
ROM_WR16(0x1e68, disp_height); /* mScrnSize */
|
||||
ROM_WR16(0x1e6e, disp_width); /* mScrnSize */
|
||||
ROM_WR16(0x1e82, disp_height); /* tScrnBitMap */
|
||||
}
|
||||
|
||||
/* FIXME: Welcome To Macintosh is drawn at the wrong position. Find where that's done. */
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rom_patch(uint8_t *rom_base)
|
||||
static int rom_patch1(uint8_t *rom_base, int disp_width, int disp_height, int mem_size)
|
||||
{
|
||||
uint32_t v = rom_get_version(rom_base);
|
||||
int r = -1;
|
||||
|
|
@ -239,8 +244,7 @@ int rom_patch(uint8_t *rom_base)
|
|||
*/
|
||||
switch(v) {
|
||||
case ROM_PLUSv3_VERSION:
|
||||
rom_patch_plusv3(rom_base);
|
||||
r = 0;
|
||||
r = rom_patch_plusv3(rom_base, disp_width, disp_height, mem_size);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -250,3 +254,103 @@ int rom_patch(uint8_t *rom_base)
|
|||
return r;
|
||||
}
|
||||
|
||||
#if defined(UMAC_STANDALONE_PATCHER)
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
uint8_t *rom_base;
|
||||
char *rom_filename = "4D1F8172 - MacPlus v3.ROM";
|
||||
char *rom_dump_filename = NULL; // Raw bytes
|
||||
char *rom_header_filename = NULL; // C header
|
||||
int ch;
|
||||
int disp_width = 512;
|
||||
int disp_height = 342;
|
||||
int ram_size = 128;
|
||||
|
||||
while ((ch = getopt(argc, argv, "vm:r:w:W:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'v':
|
||||
disp_width = 640;
|
||||
disp_height = 480;
|
||||
break;
|
||||
case 'm':
|
||||
ram_size = atoi(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
rom_filename = strdup(optarg);
|
||||
break;
|
||||
case 'W':
|
||||
rom_dump_filename = strdup(optarg);
|
||||
break;
|
||||
case 'w':
|
||||
rom_header_filename = strdup(optarg);
|
||||
break;
|
||||
case '?':
|
||||
abort();
|
||||
}
|
||||
}
|
||||
if (!rom_dump_filename && !rom_header_filename) {
|
||||
printf("Must specify either a -W (binary) or -w (C header) output file");
|
||||
abort();
|
||||
}
|
||||
printf("Opening ROM '%s'\n", rom_filename);
|
||||
int ofd = open(rom_filename, O_RDONLY);
|
||||
if (ofd < 0) {
|
||||
perror("ROM");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct stat sb;
|
||||
fstat(ofd, &sb);
|
||||
off_t _rom_size = sb.st_size;
|
||||
rom_base = mmap(0, _rom_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, ofd, 0);
|
||||
if (rom_base == MAP_FAILED) {
|
||||
printf("Can't mmap ROM!\n");
|
||||
return 1;
|
||||
}
|
||||
if (rom_patch1(rom_base, disp_width, disp_height, ram_size*1024)) {
|
||||
printf("Failed to patch ROM\n");
|
||||
return 1;
|
||||
}
|
||||
if (rom_dump_filename) {
|
||||
int rfd = open(rom_dump_filename, O_CREAT | O_TRUNC | O_RDWR, 0655);
|
||||
if (rfd < 0) {
|
||||
perror("ROM dump");
|
||||
return 1;
|
||||
}
|
||||
ssize_t written = write(rfd, rom_base, _rom_size);
|
||||
if (written < 0) {
|
||||
perror("ROM dump write");
|
||||
return 1;
|
||||
}
|
||||
if (written < _rom_size) {
|
||||
printf("*** WARNING: Short write to %s!\n",
|
||||
rom_dump_filename);
|
||||
} else {
|
||||
printf("Dumped ROM to %s\n", rom_dump_filename);
|
||||
}
|
||||
close(rfd);
|
||||
}
|
||||
if (rom_header_filename) {
|
||||
FILE *ofd = fopen(rom_header_filename, "w");
|
||||
if (!ofd) { perror("fopen"); abort(); }
|
||||
for(off_t i=0; i<_rom_size; i++) {
|
||||
fprintf(ofd, "%d,", rom_base[i]);
|
||||
if(i % 16 == 15) fprintf(ofd, "\n");
|
||||
}
|
||||
fprintf(ofd, "\n");
|
||||
printf("Dumped ROM to %s as header\n", rom_header_filename);
|
||||
fclose(ofd);
|
||||
}
|
||||
}
|
||||
#else
|
||||
int rom_patch(uint8_t *rom_base) {
|
||||
return rom_patch1(rom_base, DISP_WIDTH, DISP_HEIGHT, UMAC_MEMSIZE * 1024);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -126,6 +126,8 @@ static void scc_wr3(int AnB, uint8_t data)
|
|||
}
|
||||
}
|
||||
|
||||
int scc_get_mie() { return scc_mie; }
|
||||
|
||||
// WR9: Master Interrupt control and reset commands
|
||||
static void scc_wr9(uint8_t data)
|
||||
{
|
||||
|
|
|
|||
122
src/unix_main.c
122
src/unix_main.c
|
|
@ -27,6 +27,7 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
|
|
@ -35,6 +36,9 @@
|
|||
#include <sys/time.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#if ENABLE_AUDIO
|
||||
#include <stdatomic.h>
|
||||
#endif
|
||||
#include "SDL.h"
|
||||
|
||||
#include "rom.h"
|
||||
|
|
@ -78,6 +82,42 @@ static void copy_fb(uint32_t *fb_out, uint8_t *fb_in)
|
|||
}
|
||||
}
|
||||
|
||||
#if ENABLE_AUDIO
|
||||
// audio_callback is called from a thread, so pending_v_retrace can't be a regular variable
|
||||
atomic_int pending_v_retrace;
|
||||
static int volscale;
|
||||
uint8_t *audio_base;
|
||||
|
||||
int16_t audio[370];
|
||||
|
||||
void umac_audio_cfg(int umac_volume, int umac_sndres) {
|
||||
volscale = umac_sndres ? 0 : 65536 * umac_volume / 7;
|
||||
}
|
||||
|
||||
void umac_audio_trap() {
|
||||
int32_t offset = 128;
|
||||
uint16_t *audiodata = (uint16_t*)audio_base;
|
||||
int scale = volscale;
|
||||
if (!scale) {
|
||||
memset(audio, 0, sizeof(audio));
|
||||
return;
|
||||
}
|
||||
int16_t *stream = audio;
|
||||
for(int i=0; i<370; i++) {
|
||||
int32_t a = (*audiodata++ & 0xff) - offset;
|
||||
a = (a * scale) >> 8;
|
||||
*stream++ = a;
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_callback(void *userdata, Uint8 *stream_in, int len_bytes) {
|
||||
(void) userdata;
|
||||
assert(len_bytes == sizeof(audio));
|
||||
atomic_store(&pending_v_retrace, 1);
|
||||
memcpy(stream_in, audio, sizeof(audio));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/* The emulator core expects to be given ROM and RAM pointers,
|
||||
|
|
@ -232,7 +272,11 @@ int main(int argc, char *argv[])
|
|||
SDL_Renderer *renderer;
|
||||
SDL_Texture *texture;
|
||||
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
SDL_Init(SDL_INIT_VIDEO
|
||||
#if ENABLE_AUDIO
|
||||
| SDL_INIT_AUDIO
|
||||
#endif
|
||||
);
|
||||
SDL_Window *window = SDL_CreateWindow("umac",
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
|
|
@ -243,8 +287,14 @@ int main(int argc, char *argv[])
|
|||
perror("SDL window");
|
||||
return 1;
|
||||
}
|
||||
SDL_SetWindowGrab(window, SDL_TRUE);
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
|
||||
static const int absmouse = 1;
|
||||
if (!absmouse) {
|
||||
SDL_SetWindowGrab(window, SDL_TRUE);
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
} else {
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
}
|
||||
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
|
||||
|
||||
|
|
@ -264,25 +314,55 @@ int main(int argc, char *argv[])
|
|||
return 1;
|
||||
}
|
||||
|
||||
#if ENABLE_AUDIO
|
||||
SDL_AudioSpec desired, obtained;
|
||||
|
||||
audio_base = (uint8_t*)ram_base + umac_get_audio_offset();
|
||||
|
||||
SDL_zero(desired);
|
||||
desired.freq = 22256; // wat
|
||||
desired.channels = 1;
|
||||
desired.samples = 370;
|
||||
desired.userdata = (uint8_t*)ram_base + umac_get_audio_offset();
|
||||
desired.callback = audio_callback;
|
||||
desired.format = AUDIO_S16;
|
||||
|
||||
SDL_AudioDeviceID audio_device = SDL_OpenAudioDevice(NULL, 0, &desired, &obtained, 0);
|
||||
if (!audio_device) {
|
||||
char buf[500];
|
||||
SDL_GetErrorMsg(buf, sizeof(buf));
|
||||
printf("SDL audio_deviceSDL_GetError() -> %s\n", buf);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Emulator init
|
||||
|
||||
umac_init(ram_base, rom_base, discs);
|
||||
umac_opt_disassemble(opt_disassemble);
|
||||
|
||||
#if ENABLE_AUDIO
|
||||
// Default state is paused, this unpauses it
|
||||
SDL_PauseAudioDevice(audio_device, 0);
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Main loop
|
||||
|
||||
int done = 0;
|
||||
int mouse_button = 0;
|
||||
#if !ENABLE_AUDIO
|
||||
uint64_t last_vsync = 0;
|
||||
#endif
|
||||
uint64_t last_1hz = 0;
|
||||
do {
|
||||
struct timeval tv_now;
|
||||
SDL_Event event;
|
||||
int mousex = 0;
|
||||
int mousey = 0;
|
||||
|
||||
int send_mouse = 0;
|
||||
static int absmousex, absmousey;
|
||||
if (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_QUIT:
|
||||
|
|
@ -299,21 +379,32 @@ int main(int argc, char *argv[])
|
|||
} break;
|
||||
|
||||
case SDL_MOUSEMOTION:
|
||||
send_mouse = 1;
|
||||
absmousex = event.motion.x / DISP_SCALE;
|
||||
absmousey = event.motion.y / DISP_SCALE;
|
||||
mousex = event.motion.xrel;
|
||||
mousey = -event.motion.yrel;
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
send_mouse = 1;
|
||||
mouse_button = 1;
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
send_mouse = 1;
|
||||
mouse_button = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
umac_mouse(mousex, mousey, mouse_button);
|
||||
if (send_mouse) {
|
||||
if(absmouse) {
|
||||
umac_absmouse(absmousex, absmousey, mouse_button);
|
||||
} else {
|
||||
umac_mouse(mousex, mousey, mouse_button);
|
||||
}
|
||||
}
|
||||
|
||||
done |= umac_loop();
|
||||
|
||||
|
|
@ -321,12 +412,27 @@ int main(int argc, char *argv[])
|
|||
uint64_t now_usec = (tv_now.tv_sec * 1000000) + tv_now.tv_usec;
|
||||
|
||||
/* Passage of time: */
|
||||
if ((now_usec - last_vsync) >= 16667) {
|
||||
#if ENABLE_AUDIO
|
||||
int do_v_retrace = atomic_exchange(&pending_v_retrace, 0);
|
||||
#else
|
||||
int do_v_retrace = (now_usec - last_vsync) >= 16667;
|
||||
#endif
|
||||
if (do_v_retrace) {
|
||||
umac_vsync_event();
|
||||
last_vsync = now_usec;
|
||||
|
||||
/* Cheapo framerate limiting: */
|
||||
copy_fb(framebuffer, ram_get_base() + umac_get_fb_offset());
|
||||
|
||||
uint16_t *audioptr = (uint16_t*)((uint8_t*)ram_base + umac_get_audio_offset());
|
||||
for(int i=0; i<DISP_HEIGHT; i++) {
|
||||
int d = *audioptr++ & 0xff;
|
||||
for(int j=0; j<8; j++) {
|
||||
if (d & (1 << j)) {
|
||||
uint32_t fbdata = framebuffer[j + i * DISP_WIDTH];
|
||||
fbdata = (fbdata & ~0xff) | ((d & (1 << j)) ? 0xff : 0);
|
||||
framebuffer[j + i * DISP_WIDTH] = fbdata;
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_UpdateTexture(texture, NULL, framebuffer,
|
||||
DISP_WIDTH * sizeof (Uint32));
|
||||
/* Scales texture up to window size */
|
||||
|
|
|
|||
58
src/via.c
58
src/via.c
|
|
@ -29,6 +29,7 @@
|
|||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "m68kcpu.h"
|
||||
#include "via.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
@ -47,7 +48,8 @@
|
|||
#define VIA_T1CH 5
|
||||
#define VIA_T1LL 6
|
||||
#define VIA_T1LH 7
|
||||
#define VIA_T2CL 8
|
||||
#define VIA_T2CL 8 // write latch
|
||||
#define VIA_T2LL 8 // read counter
|
||||
#define VIA_T2CH 9
|
||||
#define VIA_SR 10
|
||||
#define VIA_ACR 11
|
||||
|
|
@ -56,6 +58,7 @@
|
|||
#define VIA_IRQ_CA 0x01
|
||||
#define VIA_IRQ_CB 0x02
|
||||
#define VIA_IRQ_SR 0x04
|
||||
#define VIA_IRQ_T2 0x20
|
||||
#define VIA_IER 14
|
||||
#define VIA_RA_ALT 15 // No-handshake version
|
||||
|
||||
|
|
@ -68,7 +71,7 @@ static const char *dbg_regnames[] = {
|
|||
"VIA_T1CH",
|
||||
"VIA_T1LL",
|
||||
"VIA_T1LH",
|
||||
"VIA_T2CL",
|
||||
"VIA_T2xL",
|
||||
"VIA_T2CH",
|
||||
"VIA_SR",
|
||||
"VIA_ACR",
|
||||
|
|
@ -84,6 +87,8 @@ static int irq_status = 0;
|
|||
static uint8_t irq_active = 0;
|
||||
static uint8_t irq_enable = 0;
|
||||
|
||||
static uint16_t via_t2c;
|
||||
|
||||
void via_init(struct via_cb *cb)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
|
|
@ -224,6 +229,24 @@ void via_write(unsigned int address, uint8_t data)
|
|||
case VIA_PCR:
|
||||
VDBG("VIA PCR %02x\n", data);
|
||||
break;
|
||||
case VIA_ACR:
|
||||
if(data & 0xe0)
|
||||
VDBG("VIA ACR %02x\n", data);
|
||||
break;
|
||||
case VIA_T2CH:
|
||||
VDBG("VIA T2CH %02x [ACR=%02x]\n", data, via_regs[VIA_ACR]);
|
||||
// writing T2CH loads the low 8 bits from the latch
|
||||
via_t2c = via_regs[VIA_T2CL] | (data << 8);
|
||||
VDBG("VIA Loaded timer 2 with %d cycles\n", via_t2c);
|
||||
if(via_t2c > 0 && GET_CYCLES() > via_t2c) {
|
||||
SET_CYCLES(via_t2c);
|
||||
}
|
||||
// writing T2CH clears associated IRQ flag
|
||||
irq_active &= ~VIA_IRQ_T2;
|
||||
break;
|
||||
case VIA_T2CL:
|
||||
VDBG("VIA T2CL %02x [ACR=%02x]\n", data, via_regs[VIA_ACR]);
|
||||
break;
|
||||
default:
|
||||
VDBG("[VIA: unhandled WR %02x to %s (reg 0x%x)]\n", data, rname, r);
|
||||
}
|
||||
|
|
@ -282,6 +305,14 @@ uint8_t via_read(unsigned int address)
|
|||
case VIA_IFR:
|
||||
data = via_read_ifr();
|
||||
break;
|
||||
|
||||
case VIA_T2LL:
|
||||
// not right, should be reduced according to cycles since
|
||||
// quantum began
|
||||
data = via_t2c & 0xff;
|
||||
// reading T2LL clears associated IRQ flag
|
||||
irq_active &= ~VIA_IRQ_T2;
|
||||
break;
|
||||
default:
|
||||
VDBG("[VIA: unhandled RD of %s (reg 0x%x)]\n", rname, r);
|
||||
}
|
||||
|
|
@ -290,10 +321,29 @@ uint8_t via_read(unsigned int address)
|
|||
return data;
|
||||
}
|
||||
|
||||
int via_limit_cycles(int cycles_in) {
|
||||
if (via_t2c > 0 && via_t2c < cycles_in) {
|
||||
return via_t2c;
|
||||
}
|
||||
return cycles_in;
|
||||
}
|
||||
|
||||
/* Time param in us */
|
||||
void via_tick(uint64_t time)
|
||||
void via_tick(int cycles)
|
||||
{
|
||||
(void)time;
|
||||
int i = via_t2c;
|
||||
if (i) {
|
||||
int old = i;
|
||||
i -= cycles;
|
||||
VDBG("Timer count down %d -> %d\n", old, i);
|
||||
if (i <= 0) {
|
||||
i = 0;
|
||||
VDBG("[VIA T2 reached zero, IRQ pending]\n");
|
||||
// irq_active |= VIA_IRQ_T2;
|
||||
via_assess_irq();
|
||||
}
|
||||
via_t2c = i;
|
||||
}
|
||||
// FIXME: support actual timers.....!
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue