st.cpp
  1  /*
  2  * Castaway
  3  *  (C) 1994 - 2002 Martin Doering, Joachim Hoenig
  4  *
  5  * IO.c - ST hardware emulation
  6  *
  7  * This file is distributed under the GPL, version 2 or at your
  8  * option any later version.  See doc/license.txt for details.
  9  *
 10  * revision history
 11  *  23.05.2002  JH  FAST1.0.1 code import: KR -> ANSI, restructuring
 12  *  09.06.2002  JH  Renamed io.c to st.c again (io.h conflicts with system headers)
 13  *  12.06.2002  JH  Correct bus error/address error exception stack frame
 14  *  14.06.2002  JH  Implemented STOP, shutdown CPU after multiple bus errors.
 15  *                  Removed inst parameter from CPU opcode functions.
 16  *  20.08.2002  JH  Fixed sign bug in DoIORW() and DoIORL()
 17  *  10.09.2002  JH  Bugfix: MOVE.L 0xfffa00,d0 and the like should not raise bus error
 18  *  16.09.2002  JH  Bugfix: Word access on unmapped I/O address stacked
 19  *                  two bus error stack frames. Fault address corrected.
 20  *                  Merged some code from JH_TOS206_patches branch.
 21  *  02.10.2002  JH  Eliminated a lot of silly bugs introduced recently. Shame on me.
 22  No more CPU bus errors from blitter.c::bitblt().
 23  *  10.10.2002  JH  Compatibility improvements.
 24  */
 25  static char     sccsid[] = "$Id: st.c,v 1.14 2002/10/10 19:41:27 jhoenig Exp $";
 26  #include <stdio.h>
 27  #include "dcastaway.h"
 28  #include "st.h"
 29  #include "mem.h"
 30  #include "m68k_intrf.h"
 31  #ifndef NO_SOUND
 32  #include "sound.h"
 33  #endif
 34  
 35  
 36  #ifdef DEBUG
 37  #include <assert.h>
 38  #endif
 39  
 40  #include <Arduino.h>
 41  
 42  #define VALUE_OPEN  0xff
 43  /*
 44  * startup display mode
 45  */
 46  int             display_mode = COL4;
 47  
 48  /*
 49  * I/O Registers
 50  */
 51  uint8           memconf;
 52  
 53  //Video shifter
 54  uint32			vid_adr;
 55  uint8           vid_baseh, vid_basem;
 56  uint32			vid_mem=0x10000;
 57  uint8           vid_syncmode=2, vid_shiftmode;
 58  int16           vid_col[16];
 59  int             vid_flag;
 60  
 61  uint16          dma_car, dma_scr, dma_sr, dma_mode;
 62  uint8           dma_adrh, dma_adrm, dma_adrl;
 63  uint8           mfp_gpip, mfp_aer, mfp_ddr, mfp_iera, mfp_ierb, mfp_ipra,
 64  mfp_iprb, mfp_isra, mfp_isrb, mfp_imra, mfp_imrb, mfp_ivr,
 65  mfp_tacr, mfp_tbcr, mfp_tcdcr, mfp_scr, mfp_ucr, mfp_rsr, mfp_tsr, mfp_udr;
 66  
 67  
 68  //Mfp delay timer variables
 69  int32 mfp_reg[12];
 70  #define	mfp_tadr mfp_reg[0]
 71  #define	mfp_tbdr mfp_reg[1]
 72  #define	mfp_tcdr mfp_reg[2]
 73  #define	mfp_tddr mfp_reg[3]
 74  #define	mfp_acount mfp_reg[4]
 75  #define	mfp_bcount mfp_reg[5]
 76  #define	mfp_ccount mfp_reg[6]
 77  #define	mfp_dcount mfp_reg[7]
 78  #define	mfp_ascale mfp_reg[8]
 79  #define	mfp_bscale mfp_reg[9]
 80  #define	mfp_cscale mfp_reg[10]
 81  #define	mfp_dscale mfp_reg[11]
 82  
 83  uint8           acia1_cr, acia1_sr, acia1_dr, acia2_cr, acia2_sr, acia2_dr;
 84  
 85  uint16          blt_halftone[16];
 86  int16           blt_src_x_inc, blt_src_y_inc;
 87  uint32          blt_src_addr;
 88  int16           blt_end_1, blt_end_2, blt_end_3;
 89  int16           blt_dst_x_inc, blt_dst_y_inc;
 90  uint32          blt_dst_addr;
 91  uint16          blt_x_cnt, blt_y_cnt;
 92  int8            blt_hop, blt_op, blt_status, blt_skew;
 93  int8            blt_ready;
 94  
 95  uint32			psg[26];
 96  //unsigned char sample[10000];
 97  #define phase0 psg[16]
 98  #define phase1 psg[17]
 99  #define phase2 psg[18]
100  #define phase3 psg[19]
101  #define psg_epos psg[20]
102  #define psgcontrol psg[21]
103  #define phase4 psg[22]
104  #define nrand psg[23]
105  #define sampos psg[24]
106  #define lastpsg psg[25]
107  
108  PROGMEM static const int samvol[16]={0,0,0,1,1,1,2,3,5,7,11,17,25,38,57,85};
109  static int samvol2[4096];
110  
111  const int32 mfpcycletab[16] = {0,80402,32161,20100,6432,5025,3216,1608,1,0,0,0,0,0,0,0};
112  
113  PROGMEM void IOInit(void)
114  {
115  	int n,a,b,c;
116  	//Create sample lookup table (4096 entries)
117  	for (a=0; a<16; a++) {
118  		for (b=0; b<16; b++) {
119  			for (c=0; c<16; c++) {
120  				samvol2[(a<<8)+(b<<4)+c]=samvol[a]+samvol[b]+samvol[c];
121  			}
122  		}
123  	}
124  	//Reset mfp variables
125  	mfp_tadr=256<<20; mfp_tbdr=256<<20; mfp_tcdr=256<<20; mfp_tddr=256<<20;
126  	mfp_tacr=0; mfp_tbcr=0; mfp_tcdcr=0;
127  	mfp_acount=256<<20; mfp_bcount=256<<20; mfp_ccount=256<<20; mfp_dcount=256<<20;
128  	mfp_ascale=0; mfp_bscale=0; mfp_cscale=0; mfp_dscale=0;
129  	for (n=0; n<24; n++) psg[n]=0;
130  	nrand=1;
131  	//Other stuff
132      vid_baseh = 0;
133      vid_basem = 0;
134      vid_shiftmode = display_mode;
135      dma_sr = 1;                 /* DMA status ready */
136      if (display_mode == MONO) {
137          mfp_gpip = 0x39;        /* no lpr, no blt, no interrupt, monochrome */
138      } else {
139          mfp_gpip = 0xb9;        /* no lpr, no blt, no interrupt, color */
140      }
141  #ifdef sun
142      act.sa_handler = Sigbus;
143      (void) sigaction (SIGBUS, &act, &oldsigbus);
144  #endif
145  #ifdef USE_MMAP
146      act.sa_handler = Sigsegv;
147      (void) sigaction (SIGSEGV, &act, &oldsigsegv);
148  #endif
149  }
150  
151  PROGMEM static void update_psg(uint8 value) {
152  #ifndef NO_SOUND
153  	Sound_Update();
154  #endif	
155  	//Update psg register
156  	psg[psgcontrol]=value;
157  	
158  	switch(psgcontrol)
159  	{
160  		case 13:
161  #ifndef NO_SOUND
162  			bEnvelopeFreqFlag = 1;
163  			bWriteEnvelopeFreq = 1;
164  #endif
165  			break;
166  		case 12:
167  			psg_epos=0;
168  			break;
169  		case 8:
170  #ifndef NO_SOUND
171  			bWriteChannelAAmp= 1;
172  #endif
173  			break;
174  		case 9:
175  #ifndef NO_SOUND
176  			bWriteChannelBAmp= 1;
177  #endif
178  			break;
179  		case 10:
180  #ifndef NO_SOUND
181  			bWriteChannelCAmp= 1;
182  #endif
183  			break;
184  	}
185  }
186  
187  PROGMEM void DoIOWB(uint32 address, uint8 value)
188  {
189  	address&=0x7fff;
190  	
191  	//Video and dma emu
192  	if (address<0x800) {
193  		switch (address) {
194  		case MEM_CONF&0x7fff:
195  			memconf = value;
196  			break;
197  		case VID_BASEH&0x7fff:
198  			vid_baseh = value;
199  			vid_mem = (vid_baseh<<16)+(vid_basem<<8);
200  			break;
201  		case VID_BASEM&0x7fff:
202  			vid_basem = value;
203  			vid_mem = (vid_baseh<<16)+(vid_basem<<8);
204  			break;
205  		case VID_SYNCMODE&0x7fff:
206  			vid_syncmode = value;
207  			maybe_border++;
208  			break;
209  		case VID_SHIFTMODE&0x7fff:
210  			vid_shiftmode = value;
211  			vid_flag=1;
212  			break;
213  		case DMA_ADRH&0x7fff:
214  			dma_adrh = value;
215  			break;
216  		case DMA_ADRM&0x7fff:
217  			dma_adrm = value;
218  			break;
219  		case DMA_ADRL&0x7fff:
220  			dma_adrl = value;
221  			break;
222  		}
223  		return;
224  	}
225  	
226  	//Sound emu
227  	if (address<0x900) {
228  #if defined(USE_FAME_CORE) && defined(USE_MOVEM_FAME_PATCH)
229  		static unsigned back_cycles=0;
230  		static unsigned back_value=0;
231  		static unsigned back_ctrl=0;
232  		static unsigned new_value=0;
233  #endif
234  		if (address<0x804)
235  			waitstate+=1;
236  		address&=3;
237  		if (address==0) {
238  			psgcontrol=value; //&15;
239  #if defined(USE_FAME_CORE) && defined(USE_MOVEM_FAME_PATCH)
240  			if ((M68KCONTEXT.cycles_counter+IO_CYCLE)==back_cycles) {
241  				psg[back_ctrl]=back_value;
242  				update_psg(new_value);
243  			}
244  #endif
245  		}else if (address==2 && psgcontrol<16) {
246  #if defined(USE_FAME_CORE) && defined(USE_MOVEM_FAME_PATCH)
247  			back_ctrl=psgcontrol;
248  			back_value=psg[psgcontrol];
249  			new_value=value;
250  #endif
251  			update_psg(value);
252  		}
253  #if defined(USE_FAME_CORE) && defined(USE_MOVEM_FAME_PATCH)
254  		back_cycles=IO_CYCLE+M68KCONTEXT.cycles_counter;
255  #endif
256  		return;
257  	}
258  	
259  	//Bus error?
260  	if (address<0xb00) {
261  		ExceptionGroup0(BUSERR, address|0xff8000, 0);
262  		return;
263  	}
264  	
265  	//MFP emu
266  	if (address<0x7c00) {
267  		waitstate+=4;
268  		switch(address) {
269  		case MFP_AER&0x7fff:
270  			mfp_aer = value;
271  			break;
272  		case MFP_DDR&0x7fff:
273  			mfp_ddr = value;
274  			break;
275  		case MFP_IERA&0x7fff:
276  			mfp_iera = value;
277  			mfp_ipra &= mfp_iera;
278  			break;
279  		case MFP_IERB&0x7fff:
280  			mfp_ierb = value;
281  			mfp_iprb &= mfp_ierb;
282  			break;
283  		case MFP_IPRA&0x7fff:
284  			mfp_ipra &= value;
285  			break;
286  		case MFP_IPRB&0x7fff:
287  			mfp_iprb &= value;
288  			break;
289  		case MFP_ISRA&0x7fff:
290  			mfp_isra &= value;
291  #ifndef USE_FAME_CORE
292  			recalc_int = 1;
293  #endif
294  			break;
295  		case MFP_ISRB&0x7fff:
296  			mfp_isrb &= value;
297  #ifndef USE_FAME_CORE
298  			recalc_int = 1;
299  #endif
300  			break;
301  		case MFP_IMRA&0x7fff:
302  			mfp_imra = value;
303  #ifndef USE_FAME_CORE
304  			recalc_int = 1;
305  #endif
306  			break;
307  		case MFP_IMRB&0x7fff:
308  			mfp_imrb = value;
309  #ifndef USE_FAME_CORE
310  			recalc_int = 1;
311  #endif
312  			break;
313  		case MFP_IVR&0x7fff:
314  			mfp_ivr = value;
315  			break;
316  		case MFP_TACR&0x7fff:
317  			mfp_tacr = value&15;
318  #if defined(USE_FAME_CORE) && defined(USE_SHORT_SLICE)
319  			if (mfp_ascale)
320  				m68k_stop_emulating();
321  #endif
322  			mfp_ascale = mfpcycletab[mfp_tacr];
323  			break;
324  		case MFP_TBCR&0x7fff:
325  			mfp_tbcr = value&15;
326  #if defined(USE_FAME_CORE) && defined(USE_SHORT_SLICE)
327  			if (mfp_bscale)
328  				m68k_stop_emulating();
329  #endif
330  			mfp_bscale = mfpcycletab[mfp_tbcr];
331  			break;
332  		case MFP_TCDCR&0x7fff:
333  			mfp_tcdcr = value&0x77;
334  #if defined(USE_FAME_CORE) && defined(USE_SHORT_SLICE)
335  			if (mfp_cscale || mfp_dscale)
336  				m68k_stop_emulating();
337  #endif
338  			mfp_cscale = mfpcycletab[mfp_tcdcr>>4];
339  			mfp_dscale = mfpcycletab[mfp_tcdcr&7];
340  			break;
341  		case MFP_TADR&0x7fff:
342  			if (value==0) mfp_tadr=256<<20; else mfp_tadr=value<<20;
343  			if (mfp_ascale==0) mfp_acount=mfp_tadr;
344  			break;
345  		case MFP_TBDR&0x7fff:
346  			if (value==0) mfp_tbdr=256<<20; else mfp_tbdr=value<<20;
347  			if (mfp_bscale==0) mfp_bcount=mfp_tbdr;
348  			break;
349  		case MFP_TCDR&0x7fff:
350  			if (value==0) mfp_tcdr=256<<20; else mfp_tcdr=value<<20;
351  			if (mfp_cscale==0) mfp_ccount=mfp_tcdr;
352  			break;
353  		case MFP_TDDR&0x7fff:
354  			if (value==0) mfp_tddr=256<<20; else mfp_tddr=value<<20;
355  			if (mfp_dscale==0) mfp_dcount=mfp_tddr;
356  			break;
357  		case MFP_SCR&0x7fff:
358  			mfp_scr = value;
359  			break;
360  		case MFP_UCR&0x7fff:
361  			mfp_ucr = value;
362  			break;
363  		case MFP_RSR&0x7fff:
364  			mfp_rsr = value;
365  			break;
366  		case MFP_TSR&0x7fff:
367  			mfp_tsr = value;
368  			break;
369  		case MFP_UDR&0x7fff:
370  			mfp_udr = value;
371  			break;
372  		}
373  		return;
374  	}
375  
376  	switch(address) {
377      case ACIA1_SR&0x7fff:
378  	waitstate+=8;
379          acia1_cr = value;
380          break;
381      case ACIA1_DR&0x7fff:
382  	waitstate+=8;
383          IkbdRecv (value);
384          break;
385      case ACIA2_SR&0x7fff:
386  	waitstate+=8;
387          acia2_cr = value;
388          break;
389      case ACIA2_DR&0x7fff:
390  	waitstate+=8;
391          break;
392  	}
393  	
394  }
395  
396  PROGMEM void DoIOWW(uint32 address, uint16 value)
397  {
398      if (address >= VID_COL0 && address <= VID_COL15) {
399          vid_col[(address & 0x1f) >> 1] = value&0x777;
400          vid_flag = 1;
401  		return;
402  	}
403  	else
404          switch (address) {
405          case DMA_MODE:
406              dma_mode = value;
407              break;
408          case DMA_CAR:
409  	    waitstate+=4;
410              if (dma_mode & 0x10) dma_scr = value;
411  			else if (dma_mode & 0x8) dma_car = value;
412  			else {
413  				switch (dma_mode & 0x6) {
414  				case 0:
415  					fdc_command = value;
416  					FDCCommand ();
417  					break;
418  				case 2:
419  					fdc_track = value;
420  					break;
421  				case 4:
422  					fdc_sector = value;
423  					break;
424  				case 6:
425  					fdc_data = value;
426  					break;
427  				}
428              }
429              break;
430          default:
431              DoIOWB(address, value>>8);
432  	    DoIOWB(address+1, value);
433              break;
434  	}
435  }
436  
437  PROGMEM void DoIOWL(uint32 address, uint32 value)
438  {
439      DoIOWW(address, value>>16);
440  	DoIOWW(address+2, value);
441  }
442  
443  static __inline__ void calculate_vid_adr(void)
444  {
445  	unsigned yet=(vid_cycle[cyclenext-IO_CYCLE]-vid_adr_cycleyet)&(~3);
446  	vid_adr+=yet;
447  	vid_adr_cycleyet+=yet;
448  }
449  
450  PROGMEM uint8 DoIORB(uint32 address)
451  {
452  	address&=0x7fff;
453  	
454      //Video and dma emu
455  	if (address<0x800) {
456  		switch (address) {
457  		case MEM_CONF&0x7fff:
458  			return memconf;
459  		case VID_BASEH&0x7fff:
460  			return vid_baseh;
461  		case VID_BASEM&0x7fff:
462  			return vid_basem;
463  		case VID_ADRH&0x7fff:
464  			calculate_vid_adr();
465  			return (unsigned char)(vid_adr>>16);
466  		case VID_ADRM&0x7fff:
467  			calculate_vid_adr();
468  			return (unsigned char)(vid_adr>>8);
469  		case VID_ADRL&0x7fff:
470  			calculate_vid_adr();
471  			return (unsigned char)(vid_adr);
472  		case VID_SYNCMODE&0x7fff:
473  			return vid_syncmode;
474  		case VID_LINEWIDTH&0x7fff:
475  			return 0xff;
476  		case VID_SHIFTMODE&0x7fff:
477  			return vid_shiftmode;
478  		case DMA_ADRH&0x7fff:
479  			return dma_adrh;
480  		case DMA_ADRM&0x7fff:
481  			return dma_adrm;
482  		case DMA_ADRL&0x7fff:
483  			return dma_adrl;
484  		}
485  		return VALUE_OPEN;
486  	}
487  	
488  	//Sound emu
489  	if (address<0x900) {
490  		address&=3;
491  		if (!address)
492  		{
493  			waitstate+=4;
494  			if (psgcontrol>=16) return 0xff;
495  			return psg[psgcontrol];
496  		}
497  		else if (address<4)
498  			waitstate++;
499  		return VALUE_OPEN;
500  	}
501  	
502  	//Bus error?
503  	if (address<0xb00) {
504  		ExceptionGroup0(BUSERR, address|0xff8000, 0);
505  		return VALUE_OPEN;
506  	}
507  	
508  	//MFP emu
509  	if (address<0x7c00) {
510  		waitstate+=4;
511  		switch(address) {
512  		case MFP_GPIP&0x7fff:
513  			return mfp_gpip;
514  		case MFP_AER&0x7fff:
515  			return mfp_aer;
516  		case MFP_DDR&0x7fff:
517  			return mfp_ddr;
518  		case MFP_IERA&0x7fff:
519  			return mfp_iera;
520  		case MFP_IERB&0x7fff:
521  			return mfp_ierb;
522  		case MFP_IPRA&0x7fff:
523  			return mfp_ipra;
524  		case MFP_IPRB&0x7fff:
525  			return mfp_iprb;
526  		case MFP_ISRA&0x7fff:
527  			return mfp_isra;
528  		case MFP_ISRB&0x7fff:
529  			return mfp_isrb;
530  		case MFP_IMRA&0x7fff:
531  			return mfp_imra;
532  		case MFP_IMRB&0x7fff:
533  			return mfp_imrb;
534  		case MFP_IVR&0x7fff:
535  			return mfp_ivr;
536  		case MFP_TACR&0x7fff:
537  			return mfp_tacr;
538  		case MFP_TBCR&0x7fff:
539  			return mfp_tbcr;
540  		case MFP_TCDCR&0x7fff:
541  			return mfp_tcdcr;
542  		case MFP_TADR&0x7fff:
543  			return (mfp_acount+0xfffff)>>20;
544  		case MFP_TBDR&0x7fff:
545  			return (mfp_bcount+0xfffff)>>20;
546  		case MFP_TCDR&0x7fff:
547  			return (mfp_ccount+0xfffff)>>20;
548  		case MFP_TDDR&0x7fff:
549  			return (mfp_dcount+0xfffff)>>20;
550  		case MFP_SCR&0x7fff:
551  			return mfp_scr;
552  		case MFP_UCR&0x7fff:
553  			return mfp_ucr;
554  		case MFP_RSR&0x7fff:
555  			return mfp_rsr;
556  		case MFP_TSR&0x7fff:
557  			return mfp_tsr;
558  		case MFP_UDR&0x7fff:
559  			return mfp_udr;
560  		}
561  		return VALUE_OPEN;
562  	}
563  	
564  	//Acia emu
565  	switch(address) {
566      case ACIA1_SR&0x7fff:
567  	waitstate+=8;
568          return 2 | acia1_sr;
569      case ACIA1_DR&0x7fff:
570  	waitstate+=8;
571          if (!(acia1_cr & 0x20)) {acia1_sr&=0x7e; mfp_gpip|=0x10;}
572          return acia1_dr;
573      case ACIA2_SR&0x7fff:
574  		waitstate+=8;
575  		return 2;
576      case ACIA2_DR&0x7fff:
577  		waitstate+=8;
578  		return 1;
579  	}
580  	return VALUE_OPEN;
581  	
582  }
583  
584  PROGMEM uint16 DoIORW(uint32 address)
585  {
586      if (address >= VID_COL0 && address <= VID_COL15) {
587          return vid_col[(address & 0x1f) >> 1];
588  	}
589      switch (address) {
590  	case DMA_SR:
591  		return dma_sr;
592  	case DMA_CAR:
593  		waitstate+=4;
594  		if (dma_mode & 0x10) return dma_scr;
595  		else if (dma_mode & 0x8) return dma_car;
596  		else {
597  			switch (dma_mode & 0x6) {
598  			case 0:
599  				if (!fdc_int) mfp_gpip |= 0x20;
600  				return fdc_status;
601  			case 2:
602  				return fdc_track;
603  			case 4:
604  				return fdc_sector;
605  			case 6:
606  				return fdc_data;
607  			}
608              return 0;
609  		}
610  	default:
611  		return (((uint32)DoIORB(address))<<8)+DoIORB(address+1);
612  	}
613  }
614  
615  PROGMEM uint32 DoIORL(uint32 address)
616  {
617  	return (((uint32)DoIORW(address))<<16)+DoIORW(address+2);
618  }
619