3335 lines
180 KiB
C++
3335 lines
180 KiB
C++
//
|
|
//
|
|
// File Name : MCL68_Plus.ino
|
|
// Used on :
|
|
// Author : Ted Fried, MicroCore Labs
|
|
// Creation : 10/25/2023
|
|
//
|
|
// Description:
|
|
// ============
|
|
//
|
|
// Drop-in replacement for the Motorola 68000
|
|
//
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// Modification History:
|
|
// =====================
|
|
//
|
|
// Revision 1 10/25/2023
|
|
// Initial revision
|
|
//
|
|
//
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// Copyright (c) 2023 Ted Fried
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
// copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
// Defines
|
|
// ----------------------------------------------------------------------
|
|
|
|
|
|
// Teensy 4.1 pin assignments
|
|
//
|
|
#define PIN_CLK 0
|
|
#define PIN_DTACK_n 1
|
|
#define PIN_VPA_n 24
|
|
#define PIN_BR_n 25
|
|
#define PIN_BGACK_n 30
|
|
|
|
#define PIN_INPUT_MUX 28 // Muxes between Data_in[15:0] and Halt/Reset/IPL[2:0]
|
|
#define PIN_DATA15_IN 27
|
|
#define PIN_DATA14_IN 26
|
|
#define PIN_DATA13_IN 39
|
|
#define PIN_DATA12_IN 38
|
|
#define PIN_DATA11_IN 21
|
|
#define PIN_DATA10_IN 20
|
|
#define PIN_DATA9_IN 23
|
|
#define PIN_DATA8_IN 22
|
|
#define PIN_DATA7_IN 16
|
|
#define PIN_DATA6_IN 17
|
|
#define PIN_DATA5_IN 41
|
|
#define PIN_DATA4_IN 40 // muxed with HALT_n
|
|
#define PIN_DATA3_IN 15 // muxed with RESET_n
|
|
#define PIN_DATA2_IN 14 // muxed with IPL[2]
|
|
#define PIN_DATA1_IN 18 // muxed with IPL[1]
|
|
#define PIN_DATA0_IN 19 // muxed with IPL[0]
|
|
|
|
#define PIN_ADDR_574_CLK 32 // CK for the 574's
|
|
#define PIN_AD_SHIFTOUT_7 13 // Shifts out Addr[23:1] and Data_out[15:0]
|
|
#define PIN_AD_SHIFTOUT_6 12
|
|
#define PIN_AD_SHIFTOUT_5 11
|
|
#define PIN_AD_SHIFTOUT_4 10
|
|
#define PIN_AD_SHIFTOUT_3 9
|
|
#define PIN_AD_SHIFTOUT_2 8
|
|
#define PIN_AD_SHIFTOUT_1 7
|
|
#define PIN_AD_SHIFTOUT_0 6
|
|
|
|
#define PIN_DATAOUT_OE_n 34 // OE for the Data_out 574's used for write cycles
|
|
#define PIN_ARB_OE_n 31 // OE for buffers when arbitration hands bus to another master
|
|
|
|
#define PIN_FC_1 35
|
|
#define PIN_FC_0 36
|
|
#define PIN_AS_n 37
|
|
#define PIN_UDS_n 5
|
|
#define PIN_LDS_n 4
|
|
#define PIN_WR_n 3
|
|
#define PIN_E 2
|
|
#define PIN_VMA_n 33
|
|
#define PIN_BG_n 29
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------------
|
|
// --------------------------------------------------------------------------------------------------
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
#define SIZE_BYTE 8
|
|
#define SIZE_WORD 16
|
|
|
|
#define ADDRESS_REG 1
|
|
#define DATA_REG 2
|
|
#define IMMEDIATE 3
|
|
#define MEMORY 4
|
|
|
|
|
|
// Calculate data sizes for different opcode encoding types
|
|
#define DATA_SIZE_TYPE_A (((0x00C0&first_opcode)>>6)==0) ? 8 : (((0x00C0&first_opcode)>>6)==1) ? 16 : 32
|
|
#define DATA_SIZE_TYPE_B (((0x3000&first_opcode)>>12)==1) ? 8 : (((0x3000&first_opcode)>>12)==3) ? 16 : 32
|
|
#define DATA_SIZE_TYPE_C (((0x0040&first_opcode)>>6)==0) ? 16 : 32
|
|
#define DATA_SIZE_TYPE_D (((0x0100&first_opcode)>>8)==0) ? 16 : 32
|
|
|
|
|
|
// Flag bits
|
|
#define mc68k_flag_T ((mc68k_flags & 0x8000) >> 15) // 15
|
|
#define mc68k_flag_S ((mc68k_flags & 0x2000) >> 13) // 13
|
|
#define mc68k_flag_INTR_Mask ((mc68k_flags & 0x0700) >> 8) // [10:8]
|
|
#define mc68k_flag_X ((mc68k_flags & 0x0010) >> 4) // 4
|
|
#define mc68k_flag_N ((mc68k_flags & 0x0008) >> 3) // 3
|
|
#define mc68k_flag_Z ((mc68k_flags & 0x0004) >> 2) // 2
|
|
#define mc68k_flag_V ((mc68k_flags & 0x0002) >> 1) // 1
|
|
#define mc68k_flag_C ( mc68k_flags & 0x0001) // 0
|
|
|
|
|
|
#define direct_intr_raw (GPIO6_raw_data&0x04000000)
|
|
#define direct_reset_raw (GPIO6_raw_data&0x02000000)
|
|
|
|
|
|
#define GPIO6_BIT_M68K_CLK 0x00000008
|
|
|
|
#define LS574_CLK_HIGH 0x00001000 // GPIO7 bit 12
|
|
#define AS_n_HIGH 0x00080000 // GPIO7 bit 19
|
|
#define AS_n_LOW 0xFFF7FFFF // GPIO7 bit 19
|
|
#define DATA_OE_n_HIGH 0x20000000 // GPIO7 bit 29
|
|
#define DATA_OE_n_LOW 0xDFFFFFFF // GPIO7 bit 29
|
|
|
|
#define WR_n_HIGH 0x00000020 // GPIO9 bit 5
|
|
#define WR_n_LOW 0xFFFFFFDF // GPIO9 bit 5
|
|
#define VMA_n_HIGH 0x00000080 // GPIO9 bit 7
|
|
#define VMA_n_LOW 0xFFFFFF7F // GPIO9 bit 7
|
|
#define BG_n_HIGH 0x80000000 // GPIO9 bit 31
|
|
#define BG_n_LOW 0x7FFFFFFF // GPIO9 bit 31
|
|
|
|
#define E_HIGH 0x00000010 // GPIO9 bit 4
|
|
#define E_LOW 0xFFFFFFEF // GPIO9 bit 4
|
|
#define UDS_n_LOW 0xFFFFFEFF // GPIO9 bit 8
|
|
#define UDS_n_HIGH 0x00000100 // GPIO9 bit 8
|
|
#define LDS_n_LOW 0xFFFFFFBF // GPIO9 bit 6
|
|
#define LDS_n_HIGH 0x00000040 // GPIO9 bit 6
|
|
#define UDS_LDS_n_HIGH 0x00000140 // GPIO9 bit 8&6
|
|
|
|
#define DTACK_n_BIT 0x00000004 // GPIO6 bit 2
|
|
#define VPA_n_BIT 0x00001000 // GPIO6 bit 12
|
|
#define BR_n_BIT 0x00002000 // GPIO6 bit 13
|
|
#define RESET_n_BIT 0x00100000 // GPIO6 bit 20
|
|
#define HALT_n_BIT 0x00080000 // GPIO6 bit 19
|
|
|
|
#define IPL2_0_BITs 0x00070000 // GPIO6 bit 18,17,16
|
|
|
|
#define ARBOE_n_HIGH 0x00400000 // GPIO8 bit 22
|
|
#define ARBOE_n_LOW 0xFFBFFFFF // GPIO8 bit 22
|
|
#define BGACK_n_BIT 0xFF7FFFFF // GPIO8 bit 23
|
|
#define INPUTMUX_n_HIGH 0x00040000 // GPIO8 bit 18
|
|
#define INPUTMUX_n_LOW 0xFFFBFFFF // GPIO8 bit 18
|
|
|
|
|
|
// Variables
|
|
// ----------------------------------------------------------------------
|
|
unsigned char biu_size;
|
|
unsigned char reg_num;
|
|
unsigned char data_size;
|
|
unsigned char EA_register;
|
|
unsigned char ea_type;
|
|
unsigned char reset_status_d;
|
|
unsigned char source_ea_type;
|
|
unsigned char destination_ea_type;
|
|
unsigned char last_mc68k_flag_T;
|
|
|
|
unsigned int last_exception=0;
|
|
unsigned int mc68k_flags=0x2700;
|
|
unsigned int biu_read_data;
|
|
unsigned int biu_dataout;
|
|
unsigned int first_opcode;
|
|
|
|
unsigned long immediate;
|
|
unsigned long m68k_data_reg[8];
|
|
unsigned long m68k_address_reg[8];
|
|
uint32_t m68k_a7_S=0x4000;
|
|
unsigned long mc68k_pc=0;
|
|
unsigned long biu_address;
|
|
unsigned long calculated_EA;
|
|
unsigned long EA_Data;
|
|
unsigned long result;
|
|
unsigned long access_address;
|
|
unsigned long source_ea;
|
|
unsigned long destination_ea;
|
|
unsigned long num=0;
|
|
unsigned long original_mc68k_pc;
|
|
|
|
|
|
int16_t clock_counter=0;
|
|
|
|
|
|
uint32_t GPIO6_raw_data=0;
|
|
uint32_t gpio6_dtack_n=0;
|
|
uint8_t mode=0;
|
|
|
|
|
|
uint8_t mc68k_fc=0x1; // Normally set to Address Space Type = User Data
|
|
|
|
uint32_t GPIO7_array[256] = {0x0,0x400,0x20000,0x20400,0x10000,0x10400,0x30000,0x30400,0x800,0xc00,0x20800,0x20c00,0x10800,0x10c00,0x30800,0x30c00,0x1,0x401,0x20001,0x20401,0x10001,0x10401,0x30001,0x30401,0x801,0xc01,0x20801,0x20c01,0x10801,0x10c01,0x30801,0x30c01,0x4,0x404,0x20004,0x20404,0x10004,0x10404,0x30004,0x30404,0x804,0xc04,0x20804,0x20c04,0x10804,0x10c04,0x30804,0x30c04,0x5,0x405,0x20005,0x20405,0x10005,0x10405,0x30005,0x30405,0x805,0xc05,0x20805,0x20c05,0x10805,0x10c05,0x30805,0x30c05,0x2,0x402,0x20002,0x20402,0x10002,0x10402,0x30002,0x30402,0x802,0xc02,0x20802,0x20c02,0x10802,0x10c02,0x30802,0x30c02,0x3,0x403,0x20003,0x20403,0x10003,0x10403,0x30003,0x30403,0x803,0xc03,0x20803,0x20c03,0x10803,0x10c03,0x30803,0x30c03,0x6,0x406,0x20006,0x20406,0x10006,0x10406,0x30006,0x30406,0x806,0xc06,0x20806,0x20c06,0x10806,0x10c06,0x30806,0x30c06,0x7,0x407,0x20007,0x20407,0x10007,0x10407,0x30007,0x30407,0x807,0xc07,0x20807,0x20c07,0x10807,0x10c07,0x30807,0x30c07,0x8,0x408,0x20008,0x20408,0x10008,0x10408,0x30008,0x30408,0x808,0xc08,0x20808,0x20c08,0x10808,0x10c08,0x30808,0x30c08,0x9,0x409,0x20009,0x20409,0x10009,0x10409,0x30009,0x30409,0x809,0xc09,0x20809,0x20c09,0x10809,0x10c09,0x30809,0x30c09,0xc,0x40c,0x2000c,0x2040c,0x1000c,0x1040c,0x3000c,0x3040c,0x80c,0xc0c,0x2080c,0x20c0c,0x1080c,0x10c0c,0x3080c,0x30c0c,0xd,0x40d,0x2000d,0x2040d,0x1000d,0x1040d,0x3000d,0x3040d,0x80d,0xc0d,0x2080d,0x20c0d,0x1080d,0x10c0d,0x3080d,0x30c0d,0xa,0x40a,0x2000a,0x2040a,0x1000a,0x1040a,0x3000a,0x3040a,0x80a,0xc0a,0x2080a,0x20c0a,0x1080a,0x10c0a,0x3080a,0x30c0a,0xb,0x40b,0x2000b,0x2040b,0x1000b,0x1040b,0x3000b,0x3040b,0x80b,0xc0b,0x2080b,0x20c0b,0x1080b,0x10c0b,0x3080b,0x30c0b,0xe,0x40e,0x2000e,0x2040e,0x1000e,0x1040e,0x3000e,0x3040e,0x80e,0xc0e,0x2080e,0x20c0e,0x1080e,0x10c0e,0x3080e,0x30c0e,0xf,0x40f,0x2000f,0x2040f,0x1000f,0x1040f,0x3000f,0x3040f,0x80f,0xc0f,0x2080f,0x20c0f,0x1080f,0x10c0f,0x3080f,0x30c0f };
|
|
|
|
uint32_t GPIO7_fcmode_array[8] = { 0x00080000, 0x000C0000, 0x20080000, 0x200C0000 , 0x00080000, 0x000C0000, 0x10080000, 0x100C0000 };
|
|
|
|
uint32_t gpio6_reset_n;
|
|
uint32_t gpio6_halt_n;
|
|
uint32_t gpio6_vpa_n;
|
|
uint32_t gpio6_ipl;
|
|
uint32_t gpio6_data=0;
|
|
|
|
uint8_t nmi_gate=0;
|
|
|
|
uint8_t sync_cycle=0;
|
|
uint16_t pfq_word_A;
|
|
uint16_t pfq_word_B;
|
|
uint8_t prefetch_queue_count=0;
|
|
uint32_t pfq_in_address;
|
|
|
|
uint32_t gpio6_br_n;
|
|
uint32_t E_input;
|
|
uint32_t E_input_d;
|
|
|
|
|
|
FASTRUN uint8_t INTERNAL_ROM[0x10000];
|
|
|
|
|
|
DMAMEM uint8_t INTERNAL_RAM1[0x40000]; // 256KB - Cant fit all 512KB in Teensy 4.1 RAM2, so splitting up
|
|
FASTRUN uint8_t INTERNAL_RAM2[0x40000]; // 256KB -
|
|
|
|
uint8_t OVERLAY = 0x1;
|
|
uint8_t write_through = 0x1;
|
|
uint8_t temp16;
|
|
uint8_t rom_readthrough=0;
|
|
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------------
|
|
// --------------------------------------------------------------------------------------------------
|
|
|
|
void setup() {
|
|
|
|
pinMode(PIN_CLK, INPUT); // GPIO6_20
|
|
pinMode(PIN_DTACK_n, INPUT); // GPIO6_20
|
|
pinMode(PIN_VPA_n, INPUT); // GPIO6_20
|
|
pinMode(PIN_BR_n, INPUT); // GPIO6_20
|
|
pinMode(PIN_BGACK_n, INPUT); // GPIO8_3
|
|
|
|
pinMode(PIN_INPUT_MUX, OUTPUT); // GPIO8_3
|
|
pinMode(PIN_DATA15_IN, INPUT); // GPIO6_20
|
|
pinMode(PIN_DATA14_IN, INPUT); // GPIO6_20
|
|
pinMode(PIN_DATA13_IN, INPUT); // GPIO6_20
|
|
pinMode(PIN_DATA12_IN, INPUT); // GPIO6_20
|
|
pinMode(PIN_DATA11_IN, INPUT); // GPIO6_20
|
|
pinMode(PIN_DATA10_IN, INPUT); // GPIO6_20
|
|
pinMode(PIN_DATA9_IN, INPUT); // GPIO6_20
|
|
pinMode(PIN_DATA8_IN, INPUT); // GPIO6_20
|
|
pinMode(PIN_DATA7_IN, INPUT); // GPIO6_20
|
|
pinMode(PIN_DATA6_IN, INPUT); // GPIO6_20
|
|
pinMode(PIN_DATA5_IN, INPUT); // GPIO6_20
|
|
pinMode(PIN_DATA4_IN, INPUT); // GPIO6_20
|
|
pinMode(PIN_DATA3_IN, INPUT); // GPIO6_20
|
|
pinMode(PIN_DATA2_IN, INPUT); // GPIO6_20
|
|
pinMode(PIN_DATA1_IN, INPUT); // GPIO6_20
|
|
pinMode(PIN_DATA0_IN, INPUT); // GPIO6_20
|
|
|
|
pinMode(PIN_ADDR_574_CLK, OUTPUT); // GPIO7_13
|
|
pinMode(PIN_AD_SHIFTOUT_7, OUTPUT); // GPIO7_13
|
|
pinMode(PIN_AD_SHIFTOUT_6, OUTPUT); // GPIO7_13
|
|
pinMode(PIN_AD_SHIFTOUT_5, OUTPUT); // GPIO7_13
|
|
pinMode(PIN_AD_SHIFTOUT_4, OUTPUT); // GPIO7_13
|
|
pinMode(PIN_AD_SHIFTOUT_3, OUTPUT); // GPIO7_13
|
|
pinMode(PIN_AD_SHIFTOUT_2, OUTPUT); // GPIO7_13
|
|
pinMode(PIN_AD_SHIFTOUT_1, OUTPUT); // GPIO7_13
|
|
pinMode(PIN_AD_SHIFTOUT_0, OUTPUT); // GPIO7_13
|
|
|
|
pinMode(PIN_DATAOUT_OE_n, OUTPUT); // GPIO7_13
|
|
pinMode(PIN_ARB_OE_n, OUTPUT); // GPIO8_3
|
|
|
|
pinMode(PIN_FC_1, OUTPUT); // GPIO7_13
|
|
pinMode(PIN_FC_0, OUTPUT); // GPIO7_13
|
|
pinMode(PIN_AS_n, OUTPUT); // GPIO7_13
|
|
pinMode(PIN_UDS_n, OUTPUT); // GPIO9_6
|
|
pinMode(PIN_LDS_n, OUTPUT); // GPIO9_6
|
|
pinMode(PIN_WR_n, OUTPUT); // GPIO9_6
|
|
pinMode(PIN_E, OUTPUT); // GPIO9_6
|
|
pinMode(PIN_VMA_n, OUTPUT); // GPIO9_6
|
|
pinMode(PIN_BG_n, OUTPUT); // GPIO9_6
|
|
|
|
|
|
// Set initial values for outputs
|
|
//
|
|
digitalWriteFast(PIN_INPUT_MUX,1);
|
|
digitalWriteFast(PIN_DATAOUT_OE_n,1);
|
|
digitalWriteFast(PIN_ARB_OE_n,0);
|
|
digitalWriteFast(PIN_FC_1,1);
|
|
digitalWriteFast(PIN_FC_0,1);
|
|
digitalWriteFast(PIN_AS_n,1);
|
|
digitalWriteFast(PIN_UDS_n,1);
|
|
digitalWriteFast(PIN_LDS_n,1);
|
|
digitalWriteFast(PIN_WR_n,1);
|
|
digitalWriteFast(PIN_VMA_n,1);
|
|
digitalWriteFast(PIN_BG_n,1);
|
|
|
|
Serial.begin(9600);
|
|
|
|
// Generate E clock output which is 1/10 the CPU clock
|
|
analogWriteFrequency(PIN_E, 780000);
|
|
analogWrite(PIN_E, 128);
|
|
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------------------------
|
|
// --------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------------
|
|
// --------------------------------------------------------------------------------------------------
|
|
//
|
|
// Begin 68000 Bus Interface Unit - BIU
|
|
//
|
|
// --------------------------------------------------------------------------------------------------
|
|
// --------------------------------------------------------------------------------------------------
|
|
|
|
void Exception_Handler(unsigned int exception_type); // Prototype
|
|
|
|
|
|
// -------------------------------------------------
|
|
// Wait for the 68000 CLK rising edge
|
|
// -------------------------------------------------
|
|
inline void wait_for_CLK_rising_edge() {
|
|
register uint32_t gpio6_data=0;
|
|
|
|
while ( (GPIO6_DR & GPIO6_BIT_M68K_CLK) != 0) {} // First ensure clock is at a low level
|
|
do { gpio6_data = GPIO6_DR; } while ( (gpio6_data & GPIO6_BIT_M68K_CLK) == 0); // Then poll for the first instance where clock is not low
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// -------------------------------------------------
|
|
// Wait for the 68000 CLK falling edge
|
|
// -------------------------------------------------
|
|
inline void wait_for_CLK_falling_edge() {
|
|
|
|
while ( (GPIO6_DR & GPIO6_BIT_M68K_CLK) == 0) {} // First ensure clock is at a low level
|
|
do { gpio6_data = GPIO6_DR; } while ( (gpio6_data & GPIO6_BIT_M68K_CLK) != 0); // Then poll for the first instance where clock is not low
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// -------------------------------------------------
|
|
// Wait for the E CLK rising edge
|
|
// -------------------------------------------------
|
|
inline void wait_for_E_rising_edge() {
|
|
register uint32_t gpio6_data=0;
|
|
|
|
while ( (GPIO6_DR & BR_n_BIT) != 0) {} // First ensure clock is at a low level
|
|
do { gpio6_data = GPIO6_DR; } while ( (gpio6_data & BR_n_BIT) == 0); // Then poll for the first instance where clock is not low
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// -------------------------------------------------
|
|
// Wait for the E CLK falling edge
|
|
// -------------------------------------------------
|
|
inline void wait_for_E_falling_edge() {
|
|
|
|
while ( (GPIO6_DR & BR_n_BIT) == 0) {} // First ensure clock is at a low level
|
|
do { gpio6_data = GPIO6_DR; } while ( (gpio6_data & BR_n_BIT) != 0); // Then poll for the first instance where clock is not low
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
// Requests BIU to perform a Data Write cycle
|
|
// ----------------------------------------------------------------------
|
|
void BIU_Write(uint32_t local_address , uint16_t local_write_data , uint8_t local_size)
|
|
{
|
|
register uint32_t muxout_clock0, muxout_clock1, muxout_clock2, muxout_clock3, muxout_clock4;
|
|
register uint32_t muxout_clock5, muxout_clock6, muxout_clock7, muxout_clock8, muxout_clock9;
|
|
register uint32_t precalculate_uls_lds;
|
|
register uint32_t address_512K;
|
|
register uint32_t address_256K;
|
|
|
|
local_address = local_address & 0xFFFFFF;
|
|
|
|
|
|
if ( (local_address==0xEFFFFE) && (local_size==8) && ((local_write_data&0x10)==0x00) ) OVERLAY=0;
|
|
if ( (local_address==0xEFFFFE) && (local_size==16) && ((local_write_data&0x1000)==0x0000) ) OVERLAY=0;
|
|
|
|
if ( (local_address==0xEFFFFE) && (local_size==8) && ((local_write_data&0x10)==0x10) ) OVERLAY=1;
|
|
if ( (local_address==v) && (local_size==16) && ((local_write_data&0x1000)==0x1000) ) OVERLAY=1;
|
|
|
|
local_size = local_size | (0x1 & local_address);
|
|
write_through=1;
|
|
|
|
|
|
// Check Alignment for Words
|
|
if ( (0x1&local_address)==1 && local_size==SIZE_WORD) { access_address=local_address; Exception_Handler(3); }
|
|
|
|
|
|
// Macintosh 512KB DRAM
|
|
//
|
|
else if ( ((OVERLAY==1) && (local_address>=0x600000) && (local_address<0x800000) ) || ( (OVERLAY==0) && (local_address<0x400000)) ) {
|
|
|
|
address_512K = local_address & 0x07FFFF; // Limit to 512K
|
|
address_256K = local_address & 0x03FFFF; // Limit to 256K
|
|
if ( (address_512K>=0x07A700) && (address_512K<0x07FC80) ) { write_through=1; } // Video Page 1 0x5580 bytes
|
|
else if ( (address_512K>=0x072700) && (address_512K<0x077C80) ) { write_through=1; } // Video Page 2
|
|
else if ( (address_512K>=0x07FD00) && (address_512K<0x07FFE4) ) { write_through=1; } // Audio Page 1 0x02E4 bytes
|
|
else if ( (address_512K>=0x07A100) && (address_512K<0x07A3E4) ) { write_through=1; } // Audio Page 2
|
|
else { write_through=0; }
|
|
|
|
if (address_512K < 0x040000) { // 0x000000 - 0x03FFFF = 256KB
|
|
if (local_size>9) { INTERNAL_RAM1[address_256K] = (local_write_data>>8); INTERNAL_RAM1[address_256K+1] = (0xFF&local_write_data); }
|
|
else { INTERNAL_RAM1[address_256K] = local_write_data; }
|
|
}
|
|
else { // 0x040000 - 0x07FFFF = 256KB
|
|
if (local_size>9) { INTERNAL_RAM2[address_256K] = (local_write_data>>8); INTERNAL_RAM2[address_256K+1] = (0xFF&local_write_data); }
|
|
else { INTERNAL_RAM2[address_256K] = local_write_data; }
|
|
}
|
|
//write_through=0;
|
|
}
|
|
|
|
|
|
|
|
if (write_through==0) {
|
|
wait_for_CLK_falling_edge();
|
|
wait_for_CLK_falling_edge();
|
|
wait_for_CLK_falling_edge();
|
|
wait_for_CLK_falling_edge();
|
|
return; }
|
|
else {
|
|
//if (OVERLAY==0) Serial.printf("local_address:%x\n\r",local_address);
|
|
|
|
if (local_size<10) { local_write_data = ( (local_write_data&0x00FF) | (local_write_data<<8)); }
|
|
|
|
// Pre-calculate GPIO7 values
|
|
//
|
|
muxout_clock0 = GPIO7_array[ (0x000000FE&local_address)>>0 | (mc68k_flag_S) ] | GPIO7_fcmode_array[mc68k_fc]; // Also asserts AS_n and DATABUS_OE_n high
|
|
muxout_clock2 = GPIO7_array[ (0x0000FF00&local_address)>>8 ] | GPIO7_fcmode_array[mc68k_fc];
|
|
muxout_clock4 = GPIO7_array[ (0x00FF0000&local_address)>>16 ] | GPIO7_fcmode_array[mc68k_fc];
|
|
muxout_clock6 = GPIO7_array[ (0x0000FF00&local_write_data)>>8 ] | GPIO7_fcmode_array[mc68k_fc];
|
|
muxout_clock8 = GPIO7_array[ (0x000000FF&local_write_data) ] | GPIO7_fcmode_array[mc68k_fc];
|
|
|
|
muxout_clock1 = muxout_clock0 | LS574_CLK_HIGH; // These are the odd words that assert the 574 clock bit high
|
|
muxout_clock3 = muxout_clock2 | LS574_CLK_HIGH; // Even bits set this bit low
|
|
muxout_clock5 = muxout_clock4 | LS574_CLK_HIGH;
|
|
muxout_clock7 = muxout_clock6 | LS574_CLK_HIGH;
|
|
muxout_clock9 = muxout_clock8 | LS574_CLK_HIGH;
|
|
|
|
|
|
|
|
noInterrupts(); // Disable Teensy interupts so the 68000 bus cycle can complete without interruption
|
|
|
|
|
|
// S0 Rising edge of CLK
|
|
// Shift out FC[2:0], Addr[23:1] and Data[15:0]
|
|
// -----------------------------------------------------------------------------
|
|
GPIO7_DR = muxout_clock0; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock1; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock2; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock3; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock4; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock5; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock6; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock7; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock8; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock9; delayNanoseconds(1);
|
|
//GPIO8_DR = GPIO8_DR & ARBOE_n_LOW; // FIX!!!!!!
|
|
|
|
|
|
/ S2 Rising edge of CLK
|
|
// - Assert AS_n, WR_n, Databus_OE_n
|
|
// -----------------------------------------------------------------------------
|
|
wait_for_CLK_rising_edge();
|
|
GPIO7_DR = muxout_clock9 & AS_n_LOW & DATA_OE_n_LOW;
|
|
GPIO9_DR = GPIO9_DR & WR_n_LOW ;
|
|
precalculate_uls_lds = ( (GPIO9_DR | UDS_n_HIGH) | LDS_n_HIGH) ;
|
|
|
|
|
|
|
|
// S3 Falling edge of CLK
|
|
// - Do nothing
|
|
// -----------------------------------------------------------------------------
|
|
wait_for_CLK_falling_edge();
|
|
switch(local_size) {
|
|
case (8): { precalculate_uls_lds = ( (GPIO9_DR & UDS_n_LOW ) | LDS_n_HIGH) ; break; }
|
|
case (9): { precalculate_uls_lds = ( (GPIO9_DR | UDS_n_HIGH) & LDS_n_LOW ) ; break; }
|
|
case (16): { precalculate_uls_lds = ( (GPIO9_DR & UDS_n_LOW ) & LDS_n_LOW ) ; break; }
|
|
case (17): { precalculate_uls_lds = ( (GPIO9_DR | UDS_n_HIGH) | LDS_n_HIGH) ; break; }
|
|
}
|
|
|
|
// S4 Rising edge of CLK
|
|
// - Assert UDS_n, LDS_n
|
|
// -----------------------------------------------------------------------------
|
|
wait_for_CLK_rising_edge();
|
|
GPIO9_DR = precalculate_uls_lds;
|
|
|
|
|
|
|
|
// S5 Falling edge of CLK
|
|
// - Poll for DTACK_n
|
|
// - Handle 6800 Bus Timing (VPA/VMA Cycles)
|
|
// - Poll for BERR_n ** Future
|
|
// -----------------------------------------------------------------------------
|
|
wait_for_CLK_falling_edge();
|
|
do { wait_for_CLK_falling_edge();
|
|
gpio6_dtack_n = GPIO6_DR & DTACK_n_BIT;
|
|
gpio6_vpa_n = GPIO6_DR & VPA_n_BIT;
|
|
} while ( (gpio6_dtack_n != 0) && ( gpio6_vpa_n != 0) );
|
|
|
|
|
|
|
|
if ( gpio6_vpa_n == 0) {
|
|
|
|
wait_for_E_falling_edge();
|
|
|
|
wait_for_CLK_falling_edge();
|
|
wait_for_CLK_falling_edge();
|
|
GPIO9_DR = GPIO9_DR & VMA_n_LOW; // Assert VMA_n
|
|
|
|
wait_for_E_rising_edge();
|
|
wait_for_E_falling_edge();
|
|
|
|
GPIO7_DR = (muxout_clock9 | AS_n_HIGH | DATA_OE_n_HIGH);
|
|
GPIO9_DR = GPIO9_DR | UDS_LDS_n_HIGH | VMA_n_HIGH | WR_n_HIGH;
|
|
|
|
interrupts(); // Re-enable Teensy's interrupts so the UART and downloading works
|
|
return;
|
|
}
|
|
|
|
|
|
// S6 Rising edge of CLK
|
|
// - Do nothing
|
|
// -----------------------------------------------------------------------------
|
|
wait_for_CLK_rising_edge();
|
|
|
|
|
|
// S7 Falling edge of CLK
|
|
// - Deassert AS_n, UDS_n, LDS_n
|
|
// -----------------------------------------------------------------------------
|
|
wait_for_CLK_falling_edge();
|
|
GPIO7_DR = muxout_clock9 | AS_n_HIGH | DATA_OE_n_HIGH;
|
|
GPIO9_DR = GPIO9_DR | UDS_LDS_n_HIGH | WR_n_HIGH;
|
|
|
|
|
|
interrupts(); // Re-enable Teensy's interrupts so the UART and downloading works
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Requests BIU to perform a Read cycle
|
|
// ----------------------------------------------------------------------
|
|
uint16_t BIU_Read(uint32_t local_address , uint8_t local_size)
|
|
{
|
|
register uint32_t muxout_clock0, muxout_clock1, muxout_clock2, muxout_clock3, muxout_clock4;
|
|
register uint32_t muxout_clock5, muxout_clock6, muxout_clock7, muxout_clock8, muxout_clock9;
|
|
register uint32_t precalculate_uls_lds;
|
|
uint16_t read_data;
|
|
|
|
local_address = local_address & 0xFFFFFF;
|
|
|
|
local_size = local_size | (0x1 & local_address);
|
|
|
|
|
|
// Check Alignment for Words
|
|
if ( (0x1&local_address)==1 && local_size==SIZE_WORD) { access_address=local_address; Exception_Handler(3); return 0xEEEE;}
|
|
|
|
|
|
// ROM 64KB
|
|
if ( (rom_readthrough==0) && ((OVERLAY==1) && (local_address<0x600000)) || ((OVERLAY==0) && (rom_readthrough==0) && (local_address>=0x400000) &&(local_address<0x800000)) ) {
|
|
local_address = local_address & 0x00FFFF; // Limit to 64K
|
|
if (local_size>9) { read_data = (INTERNAL_ROM[local_address]<<8) | INTERNAL_ROM[local_address+1]; }
|
|
else { read_data = INTERNAL_ROM[local_address];}
|
|
wait_for_CLK_falling_edge();
|
|
wait_for_CLK_falling_edge();
|
|
wait_for_CLK_falling_edge();
|
|
wait_for_CLK_falling_edge();
|
|
return read_data;
|
|
}
|
|
|
|
// RAM 512KB
|
|
else if ( ((OVERLAY==1) && (local_address>=0x600000) && (local_address<0x800000) ) || ( (OVERLAY==0) && (local_address<0x400000)) ) {
|
|
local_address = local_address & 0x07FFFF; // Limit to 512K
|
|
if (local_address < 0x040000) { // 0x000000 - 0x03FFFF = 256KB
|
|
if (local_size>9) { read_data = (INTERNAL_RAM1[local_address]<<8) | INTERNAL_RAM1[local_address+1]; }
|
|
else { read_data = INTERNAL_RAM1[local_address];}
|
|
}
|
|
else { // 0x040000 - 0x07FFFF = 256KB
|
|
local_address = local_address - 0x040000;
|
|
if (local_size>9) { read_data = (INTERNAL_RAM2[local_address]<<8) | INTERNAL_RAM2[local_address+1]; }
|
|
else { read_data = INTERNAL_RAM2[local_address];}
|
|
}
|
|
wait_for_CLK_falling_edge();
|
|
wait_for_CLK_falling_edge();
|
|
wait_for_CLK_falling_edge();
|
|
wait_for_CLK_falling_edge();
|
|
return read_data;
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
// Pre-calculate GPIO7 values
|
|
//
|
|
muxout_clock0 = GPIO7_array[ (0x000000FE&local_address)>>0 | (mc68k_flag_S) ] | GPIO7_fcmode_array[mc68k_fc]; // Also asserts AS_n and DATABUS_OE_n high
|
|
muxout_clock2 = GPIO7_array[ (0x0000FF00&local_address)>>8 ] | GPIO7_fcmode_array[mc68k_fc];
|
|
muxout_clock4 = GPIO7_array[ (0x00FF0000&local_address)>>16 ] | GPIO7_fcmode_array[mc68k_fc];
|
|
muxout_clock6 = GPIO7_array[ 0x0 ] | GPIO7_fcmode_array[mc68k_fc];
|
|
muxout_clock8 = GPIO7_array[ 0x0 ] | GPIO7_fcmode_array[mc68k_fc];
|
|
|
|
muxout_clock1 = muxout_clock0 | LS574_CLK_HIGH; // These are the odd words that assert the 574 clock bit high
|
|
muxout_clock3 = muxout_clock2 | LS574_CLK_HIGH; // Even bits set this bit low
|
|
muxout_clock5 = muxout_clock4 | LS574_CLK_HIGH;
|
|
muxout_clock7 = muxout_clock6 | LS574_CLK_HIGH;
|
|
muxout_clock9 = muxout_clock8 | LS574_CLK_HIGH | DATA_OE_n_HIGH;
|
|
|
|
|
|
|
|
noInterrupts(); // Disable Teensy interupts so the 68000 bus cycle can complete without interruption
|
|
|
|
|
|
// S0 Rising edge of CLK
|
|
// Shift out FC[2:0], Addr[23:1] and Data[15:0]
|
|
// -----------------------------------------------------------------------------
|
|
GPIO7_DR = muxout_clock0; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock1; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock2; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock3; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock4; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock5; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock6; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock7; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock8; delayNanoseconds(1);
|
|
GPIO7_DR = muxout_clock9;
|
|
//GPIO8_DR = GPIO8_DR & ARBOE_n_LOW; // FIX!!!!!!
|
|
precalculate_uls_lds = ( (GPIO9_DR | UDS_n_HIGH) | LDS_n_HIGH) ;
|
|
|
|
|
|
switch(local_size) {
|
|
case (8): { precalculate_uls_lds = ( (GPIO9_DR & UDS_n_LOW ) | LDS_n_HIGH) ; break; }
|
|
case (9): { precalculate_uls_lds = ( (GPIO9_DR | UDS_n_HIGH) & LDS_n_LOW ) ; break; }
|
|
case (16): { precalculate_uls_lds = ( (GPIO9_DR & UDS_n_LOW ) & LDS_n_LOW ) ; break; }
|
|
case (17): { precalculate_uls_lds = ( (GPIO9_DR | UDS_n_HIGH) | LDS_n_HIGH) ; break; }
|
|
}
|
|
//if (local_address>0xE00000) Serial.printf("local_address: %x local_size:%x\n\r",local_address,local_size);
|
|
|
|
|
|
|
|
// S2 Rising edge of CLK
|
|
// - Assert AS_n
|
|
// - Assert UDS_n, LDS_n
|
|
// -----------------------------------------------------------------------------
|
|
wait_for_CLK_rising_edge();
|
|
GPIO7_DR = muxout_clock9 & AS_n_LOW;
|
|
GPIO9_DR = precalculate_uls_lds | 0x80;
|
|
|
|
// S3 Falling edge of CLK
|
|
// - Store the values for RESET_n, HALT_n
|
|
// -----------------------------------------------------------------------------
|
|
wait_for_CLK_falling_edge();
|
|
sync_cycle=0;
|
|
digitalWriteFast(PIN_INPUT_MUX,0);
|
|
|
|
|
|
// S4 Rising edge of CLK
|
|
// - Do nothing
|
|
// -----------------------------------------------------------------------------
|
|
wait_for_CLK_rising_edge();
|
|
|
|
|
|
|
|
// S5 Falling edge of CLK
|
|
// - Poll for DTACK_n
|
|
// - Handle 6800 Bus Timing (VPA/VMA Cycles)
|
|
// - Poll for BERR_n ** Future
|
|
// -----------------------------------------------------------------------------
|
|
wait_for_CLK_falling_edge();
|
|
do { wait_for_CLK_falling_edge();
|
|
gpio6_dtack_n = GPIO6_DR & DTACK_n_BIT;
|
|
gpio6_vpa_n = GPIO6_DR & VPA_n_BIT;
|
|
} while ( (gpio6_dtack_n != 0) && ( gpio6_vpa_n != 0) );
|
|
|
|
|
|
if ( gpio6_vpa_n == 0) {
|
|
sync_cycle=1;
|
|
|
|
wait_for_E_falling_edge();
|
|
|
|
wait_for_CLK_falling_edge();
|
|
wait_for_CLK_falling_edge();
|
|
GPIO9_DR = GPIO9_DR & VMA_n_LOW; // Assert VMA_n
|
|
|
|
wait_for_E_rising_edge();
|
|
wait_for_E_falling_edge();
|
|
|
|
GPIO7_DR = (muxout_clock9 | AS_n_HIGH | DATA_OE_n_HIGH);
|
|
GPIO9_DR = GPIO9_DR | UDS_LDS_n_HIGH | VMA_n_HIGH;
|
|
read_data = GPIO6_DR >> 16;
|
|
digitalWriteFast(PIN_INPUT_MUX,1);
|
|
|
|
if (local_size==8) { read_data = (read_data>>8); }
|
|
else if (local_size==9) { read_data = (read_data&0x00FF); }
|
|
|
|
|
|
interrupts(); // Re-enable Teensy's interrupts so the UART and downloading works
|
|
|
|
if ( (local_address&0xFF0000)==0xF80000) read_data = 0xFFFF;
|
|
|
|
return read_data;
|
|
}
|
|
|
|
|
|
// S6 Rising edge of CLK
|
|
// - Steer the '257 to pass read data
|
|
// -----------------------------------------------------------------------------
|
|
wait_for_CLK_rising_edge();
|
|
|
|
|
|
|
|
// S7 Falling edge of CLK
|
|
// - Deassert AS_n, UDS_n, LDS_n
|
|
// - Sample the Data Bus
|
|
// - Steer the '257 to pass the reset, halt, IPL, BERR
|
|
// -----------------------------------------------------------------------------
|
|
wait_for_CLK_falling_edge();
|
|
GPIO7_DR = muxout_clock9 | AS_n_HIGH | DATA_OE_n_HIGH;
|
|
GPIO9_DR = GPIO9_DR | UDS_LDS_n_HIGH;
|
|
|
|
read_data = gpio6_data >> 16;
|
|
digitalWriteFast(PIN_INPUT_MUX,1);
|
|
|
|
|
|
if (local_size==8) { read_data = (read_data>>8); }
|
|
else if (local_size==9) { read_data = (read_data&0x00FF); }
|
|
|
|
interrupts(); // Re-enable Teensy's interrupts so the UART and downloading works
|
|
|
|
|
|
return read_data;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Requests BIU to perform an Interrupt IACK cycle
|
|
// ----------------------------------------------------------------------
|
|
uint8_t BIU_IACK() {
|
|
uint8_t local_fc_copy;
|
|
uint32_t local_address;
|
|
uint16_t local_data;
|
|
//uint8_t local_intr_mask;
|
|
|
|
// local_intr_mask=mc68k_flag_INTR_Mask; //Serial.printf("BIU_IACK\n\r");
|
|
|
|
local_fc_copy = mc68k_fc;
|
|
mc68k_fc = 0x7; // Set to Address Space Type = CPU Space for IACK
|
|
local_address = 0xFFFFFFF1 | (gpio6_ipl << 1); // Set Address output for IACK
|
|
local_data = BIU_Read(local_address, SIZE_BYTE); // Read the vector
|
|
|
|
if (sync_cycle==1) local_data = 0x18 + gpio6_ipl; // Autovector Interrupt = 0x18 + the IPL number
|
|
|
|
mc68k_fc = local_fc_copy;
|
|
return local_data;
|
|
}
|
|
|
|
|
|
// BIU Read 32 bits
|
|
// ----------------------------------------------------------------------
|
|
unsigned long BIU_Read_32(unsigned long local_address)
|
|
{
|
|
return (BIU_Read(local_address , 16) << 16) | BIU_Read(local_address+0x2 , 16);
|
|
}
|
|
|
|
|
|
// BIU Write 32 bits
|
|
// ----------------------------------------------------------------------
|
|
void BIU_Write_32(unsigned long local_address , unsigned long local_data )
|
|
{
|
|
BIU_Write(local_address , (0xFFFF0000&local_data)>>16 , 16); // Write upper word of the 32-bit data
|
|
BIU_Write(local_address+0x2, (0x0000FFFF&local_data) , 16); // Write lower word of the 32-bit data at next word address
|
|
return;
|
|
}
|
|
|
|
|
|
// Add a word to the prefetch queue
|
|
// ------------------------------------------------------
|
|
void BIU_PFQ_add_word() {
|
|
uint16_t local_word;
|
|
|
|
if (prefetch_queue_count>1) return; // Prefetch queue limited to two words
|
|
|
|
mc68k_fc = ((mc68k_flags & 0x2000) >> 11) | 0x2; // Set FC to Address Space Type = Program
|
|
local_word = BIU_Read(pfq_in_address , SIZE_WORD); // Fetch the word
|
|
mc68k_fc = ((mc68k_flags & 0x2000) >> 11) | 0x1; // Return FC to Address Space Type = Data
|
|
|
|
pfq_in_address = pfq_in_address + 2;
|
|
|
|
|
|
switch(prefetch_queue_count) {
|
|
case 0: pfq_word_A = local_word; break;
|
|
case 1: pfq_word_B = local_word; break;
|
|
}
|
|
prefetch_queue_count++;
|
|
//Serial.printf("PFQ %d %x %x\n\r",prefetch_queue_count-1,pfq_word_A,pfq_word_B);
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// Fetch a word from the prefetch queue
|
|
// ------------------------------------------------------
|
|
uint16_t BIU_PFQ_Fetch() {
|
|
uint16_t pfq_top_word;
|
|
|
|
if (prefetch_queue_count==0) BIU_PFQ_add_word(); // Prefetch queue empty, so must fill at least one word in the queue
|
|
|
|
pfq_top_word = pfq_word_A;
|
|
pfq_word_A = pfq_word_B;
|
|
pfq_word_B = 0x00;
|
|
prefetch_queue_count--;
|
|
|
|
mc68k_pc = mc68k_pc + 2;
|
|
//Serial.printf("PFQ Fetchiing %x %d %x %x\n\r",pfq_top_word,prefetch_queue_count,pfq_word_A,pfq_word_B);
|
|
//Serial.printf("%x ",pfq_top_word);
|
|
return pfq_top_word;
|
|
}
|
|
|
|
|
|
// Flushes the prefetch queue and begins fetching instructions from the new PC address
|
|
// -------------------------------------------------------------------------------------
|
|
void BIU_Jump(uint32_t jump_address) {
|
|
jump_address = 0xFFFFFFFF & jump_address;
|
|
|
|
// Check Alignment for Words
|
|
if ( (0x1&jump_address)==1) { access_address=jump_address; Exception_Handler(3); }
|
|
else
|
|
{
|
|
mc68k_pc = jump_address; // Set PC to the Jump Address
|
|
|
|
prefetch_queue_count = 0; // Flush the Prefetch Queue
|
|
pfq_in_address = mc68k_pc;
|
|
}
|
|
return;
|
|
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------------------------
|
|
// --------------------------------------------------------------------------------------------------
|
|
//
|
|
// End MC68000 Bus Interface Unit
|
|
//
|
|
// --------------------------------------------------------------------------------------------------
|
|
// --------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// Write data back to the Data register pool with the correct data size
|
|
// ----------------------------------------------------------------------
|
|
void Store_Data_Register(unsigned char reg_num , unsigned long reg_data , unsigned char reg_size)
|
|
{
|
|
if (reg_size==8) { m68k_data_reg[reg_num] = ( (m68k_data_reg[reg_num]&0xFFFFFF00) | (reg_data&0x000000FF) ); }
|
|
else if (reg_size==16) { m68k_data_reg[reg_num] = ( (m68k_data_reg[reg_num]&0xFFFF0000) | (reg_data&0x0000FFFF) ); }
|
|
else if (reg_size==32) { m68k_data_reg[reg_num] = (reg_data&0xFFFFFFFF); }
|
|
return;
|
|
}
|
|
|
|
// Read data from the Data register pool
|
|
// ----------------------------------------------------------------------
|
|
unsigned long Fetch_Data_Register(unsigned char reg_num , unsigned char size)
|
|
{
|
|
if (size==8) { return (m68k_data_reg[reg_num]&0x000000FF); }
|
|
else if (size==16) { return (m68k_data_reg[reg_num]&0x0000FFFF); }
|
|
else if (size==32) { return (m68k_data_reg[reg_num]&0xFFFFFFFF); }
|
|
else return 0xEEEEEEEE;
|
|
}
|
|
|
|
|
|
// Return the sign-extended value of a B/W/L register
|
|
// ----------------------------------------------------------------------
|
|
unsigned long Sign_Extend(unsigned long reg_data , unsigned char reg_size)
|
|
{
|
|
if (reg_size==8)
|
|
{
|
|
if ((reg_data&0x0080)!=0x0) { return (reg_data | 0xFFFFFF00); } else { return (reg_data & 0x000000FF); }
|
|
}
|
|
else if (reg_size==16)
|
|
{
|
|
if ((reg_data&0x8000)!=0x0) { return (reg_data | 0xFFFF0000); } else { return (reg_data & 0x0000FFFF); }
|
|
}
|
|
else { return (reg_data&0xFFFFFFFF); }
|
|
}
|
|
|
|
|
|
// Write data back to the Address register pool
|
|
// Byte writes cause an exception
|
|
// Write back to the proper SP (A7) depending on the Supervisor mode
|
|
// ----------------------------------------------------------------------
|
|
void Store_Address_Register(unsigned char reg_num , unsigned long reg_data , unsigned char reg_size)
|
|
{
|
|
if (reg_size==8) { Exception_Handler(3); }
|
|
|
|
else if (mc68k_flag_S==1 && reg_num==0x7) { m68k_a7_S = (reg_data&0xFFFFFFFF); }
|
|
else { m68k_address_reg[reg_num] = (reg_data&0xFFFFFFFF); }
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
// Read data from the Address register pool
|
|
// ----------------------------------------------------------------------
|
|
unsigned long Fetch_Address_Register(unsigned char reg_num , unsigned char size)
|
|
{
|
|
if (mc68k_flag_S==1 && reg_num==0x7) return m68k_a7_S;
|
|
|
|
else return m68k_address_reg[reg_num];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate the selected condition results
|
|
// ----------------------------------------------------------------------
|
|
unsigned char Test_Condition(unsigned int local_opcode)
|
|
{
|
|
unsigned int condition_code;
|
|
|
|
condition_code = (local_opcode&0x0F00) >> 8; // Isolate opcode bits[11:8]
|
|
|
|
switch(condition_code)
|
|
{
|
|
case 0x0: return TRUE; // Always
|
|
case 0x1: return FALSE; // Never
|
|
case 0x2: if (mc68k_flag_C==0 && mc68k_flag_Z==0) return TRUE; else return FALSE; // Higher Than C=0 AND Z=0
|
|
case 0x3: if (mc68k_flag_C==1 || mc68k_flag_Z==1) return TRUE; else return FALSE; // Lower or Same C=1 OR Z=1
|
|
case 0x4: if (mc68k_flag_C==0) return TRUE; else return FALSE; // Carry Clear C=0
|
|
case 0x5: if (mc68k_flag_C==1) return TRUE; else return FALSE; // Carry Set C=1
|
|
case 0x6: if (mc68k_flag_Z==0) return TRUE; else return FALSE; // Not Equal Z=0
|
|
case 0x7: if (mc68k_flag_Z==1) return TRUE; else return FALSE; // Equal Z=1
|
|
case 0x8: if (mc68k_flag_V==0) return TRUE; else return FALSE; // V Clear V=0
|
|
case 0x9: if (mc68k_flag_V==1) return TRUE; else return FALSE; // V Set V=1
|
|
case 0xA: if (mc68k_flag_N==0) return TRUE; else return FALSE; // Plus N=0
|
|
case 0xB: if (mc68k_flag_N==1) return TRUE; else return FALSE; // Minus N=1
|
|
case 0xC: if (mc68k_flag_N == mc68k_flag_V) return TRUE; else return FALSE; // Greater or Equal N=V
|
|
case 0xD: if (mc68k_flag_N != mc68k_flag_V) return TRUE; else return FALSE; // Less Than N!=V
|
|
case 0xE: if ((mc68k_flag_N==mc68k_flag_V) && mc68k_flag_Z==0) return TRUE; else return FALSE; // Greater Than N=V AND Z=0
|
|
case 0xF: if ((mc68k_flag_N!=mc68k_flag_V) || mc68k_flag_Z==1) return TRUE; else return FALSE; // Less Than or Equal N!=V AND Z=1
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Push a word to the Stack
|
|
// ----------------------------------------------------------------------
|
|
void Push(unsigned int push_data)
|
|
{
|
|
|
|
if (mc68k_flag_S==0x0)
|
|
{
|
|
m68k_address_reg[7] = m68k_address_reg[7] - 0x2;
|
|
BIU_Write(m68k_address_reg[7] , push_data, SIZE_WORD);
|
|
}
|
|
else
|
|
{
|
|
m68k_a7_S = m68k_a7_S - 0x2;
|
|
BIU_Write(m68k_a7_S , push_data, SIZE_WORD);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
// Pop a word to from the Stack
|
|
// ----------------------------------------------------------------------
|
|
unsigned int Pop()
|
|
{
|
|
unsigned int temp=0;
|
|
|
|
if (mc68k_flag_S==0x0)
|
|
{
|
|
temp = BIU_Read(m68k_address_reg[7] , SIZE_WORD);
|
|
m68k_address_reg[7] = m68k_address_reg[7] + 0x2;
|
|
}
|
|
else
|
|
{
|
|
temp = BIU_Read(m68k_a7_S , SIZE_WORD);
|
|
m68k_a7_S = m68k_a7_S + 0x2;
|
|
}
|
|
return temp;
|
|
}
|
|
|
|
|
|
// Runs Reset routine to put CPU back to initial conditions
|
|
// ----------------------------------------------------------------------
|
|
void Reset_routine()
|
|
{
|
|
unsigned long pc_temp=0;
|
|
|
|
OVERLAY=1;
|
|
|
|
for (uint32_t i=0x7FA700 ; i<=0x7FFF00 ; i=i+1) { BIU_Write(i, random(0,0xFF) , SIZE_BYTE); } delay(1000);
|
|
for (uint32_t i=0x7FA700 ; i<=0x7FFF00 ; i=i+1) { BIU_Write(i, random(0,0xFF) , SIZE_BYTE); } delay(1000);
|
|
|
|
|
|
do { wait_for_CLK_falling_edge();
|
|
gpio6_reset_n = gpio6_data & RESET_n_BIT;
|
|
gpio6_halt_n = gpio6_data & HALT_n_BIT;
|
|
} while ((gpio6_reset_n == 0) && (gpio6_halt_n == 0) ); // Wait here until RESET_n and HALT_n signal de-asserted
|
|
|
|
|
|
mc68k_flags=0x2700; // Initialize flags T=0, S=1, Mask=111
|
|
|
|
BIU_Jump(0x000000); // Flush prefetch queue and start fetching data at address 0x00
|
|
|
|
m68k_a7_S = BIU_PFQ_Fetch(); // Fetch upper word of the Supervisor Stack Pointer
|
|
|
|
m68k_a7_S = (m68k_a7_S<<16) | BIU_PFQ_Fetch(); // Fetch lower word of the Supervisor Stack Pointer
|
|
|
|
pc_temp = BIU_PFQ_Fetch(); // Fetch upper word of the Program Counter
|
|
mc68k_pc = (pc_temp<<16) | BIU_PFQ_Fetch(); // Fetch lower word of the Program Counter
|
|
|
|
BIU_Jump(mc68k_pc); // Jump to the new PC
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void Exception_Handler(unsigned int vector_number)
|
|
{
|
|
unsigned int temp=0;
|
|
unsigned int mc68k_flags_copy=0x2700;
|
|
unsigned long exception_address=0;
|
|
|
|
last_exception = vector_number; // Store the value of this exception
|
|
|
|
mc68k_flags_copy = mc68k_flags; // Store the original Flags register value
|
|
temp = mc68k_flags | 0x2000; // Set the S flag
|
|
temp = temp & 0x7FFF; // Clear the T flag
|
|
mc68k_flags = temp; // Update the System Flags
|
|
|
|
if (vector_number==0x8) clock_counter=6;
|
|
|
|
if (vector_number <= 3) // Additional data is stacked for Group 0
|
|
{
|
|
//Push(BIU_Get_Failed_Access_Type()); // Stack the BIU Access Type
|
|
clock_counter=50;
|
|
Push(0x5B); // !! Set to 0x5A for now
|
|
Push(access_address&0xFFFF); // Stack the lower portion of the failed access address
|
|
Push(access_address>>16); // Stack the upper portion of the failed access address
|
|
Push(first_opcode); // Stack the Opcode
|
|
}
|
|
|
|
if (vector_number==99) // 0x99=Interrupt -- Fetch the vector number from the BIU
|
|
{
|
|
clock_counter=12;
|
|
temp = mc68k_flags & 0xF8FF; // Clear the Interrupt Flags
|
|
mc68k_flags = (temp | (gpio6_ipl<<8) ); // Set the Interrupt Flags to the current IRQ from the BIU
|
|
vector_number = BIU_IACK(); // Fetch the vector from the BIU IACK Cycle
|
|
}
|
|
|
|
if ( (vector_number == 10) || (vector_number == 11) ) { // for the Line-A and Line-F trap the PC is 2 less
|
|
clock_counter=6;
|
|
mc68k_pc -=2 ;
|
|
}
|
|
|
|
Push(mc68k_pc&0xFFFF); // Stack the lower PC
|
|
Push(mc68k_pc>>16); // Stack the upper PC
|
|
Push(mc68k_flags_copy); // Stack the Original copy of the Flags
|
|
|
|
exception_address = BIU_Read_32(vector_number<<2); // Fetch the 32-bit exception address
|
|
BIU_Jump(exception_address); // Jump to the exception address
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_BOOL_I_TO_CCR(unsigned char bool_type)
|
|
{
|
|
clock_counter=8;
|
|
if (bool_type==1) mc68k_flags = (0xFF00&mc68k_flags) | ( (0x00FF&mc68k_flags) | (0x001F&BIU_PFQ_Fetch()) ); else
|
|
if (bool_type==2) mc68k_flags = (0xFF00&mc68k_flags) | ( (0x00FF&mc68k_flags) & (0x001F&BIU_PFQ_Fetch()) ); else
|
|
if (bool_type==3) mc68k_flags = (0xFF00&mc68k_flags) | ( (0x00FF&mc68k_flags) ^ (0x001F&BIU_PFQ_Fetch()) );
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_BOOL_I_TO_SR(unsigned char bool_type)
|
|
{
|
|
if (mc68k_flag_S==0x0) { Exception_Handler(8); } // Verify that supervisor privilege is set
|
|
else
|
|
{
|
|
clock_counter=clock_counter+8;
|
|
if (bool_type==1) mc68k_flags = (mc68k_flags | BIU_PFQ_Fetch() ); else
|
|
if (bool_type==2) mc68k_flags = (mc68k_flags & BIU_PFQ_Fetch() ); else
|
|
if (bool_type==3) mc68k_flags = (mc68k_flags ^ BIU_PFQ_Fetch() );
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
unsigned long Calculate_EA(unsigned int allowed_modes)
|
|
{
|
|
unsigned long address_register;
|
|
unsigned long temp_address;
|
|
unsigned long ea_extension;
|
|
unsigned long offset=0;
|
|
unsigned long extension_displacement;
|
|
unsigned long extension_register;
|
|
unsigned char ea_A_bit;
|
|
unsigned char ea_L_bit;
|
|
|
|
|
|
ea_type=99; // Reset ea_type value
|
|
|
|
EA_register =(0x0007&first_opcode);
|
|
|
|
switch( (0x0038&first_opcode)>>3 )
|
|
{
|
|
case 0x0: if ((0x2000&allowed_modes)==0) Exception_Handler(4); else // Dn
|
|
{ ea_type=DATA_REG;
|
|
return (EA_register);
|
|
} break;
|
|
|
|
case 0x1: if ((0x1000&allowed_modes)==0) Exception_Handler(4); else // An
|
|
{ ea_type=ADDRESS_REG;
|
|
return (EA_register);
|
|
} break;
|
|
|
|
case 0x2: if ((0x0800&allowed_modes)==0) Exception_Handler(4); else // (An)
|
|
{ ea_type=MEMORY;
|
|
address_register=Fetch_Address_Register(EA_register,32);
|
|
return address_register;
|
|
} break;
|
|
|
|
case 0x3: if ((0x0400&allowed_modes)==0) Exception_Handler(4); else // (An)+
|
|
{ ea_type=MEMORY;
|
|
address_register=Fetch_Address_Register(EA_register,32);
|
|
temp_address = address_register;
|
|
address_register = (data_size==8 && EA_register==0x7) ? address_register+2 : // Special case for SSP
|
|
(data_size==8) ? address_register+1 :
|
|
(data_size==16) ? address_register+2 :
|
|
address_register+4 ;
|
|
Store_Address_Register(EA_register, address_register , 32);
|
|
return temp_address;
|
|
} break;
|
|
|
|
case 0x4: if ((0x0200&allowed_modes)==0) Exception_Handler(4); else // -(An)
|
|
{ clock_counter=clock_counter+2;
|
|
ea_type=MEMORY;
|
|
address_register=Fetch_Address_Register(EA_register,32);
|
|
address_register = (data_size==8 && EA_register==0x7) ? address_register-2 : // Special case for SSP
|
|
(data_size==8) ? address_register-1 :
|
|
(data_size==16) ? address_register-2 :
|
|
address_register-4 ;
|
|
Store_Address_Register(EA_register, address_register , 32);
|
|
return address_register;
|
|
} break;
|
|
|
|
case 0x5: if ((0x0100&allowed_modes)==0) Exception_Handler(4); else // d16(An)
|
|
{ ea_type=MEMORY;
|
|
address_register=Fetch_Address_Register(EA_register,32);
|
|
offset=Sign_Extend(BIU_PFQ_Fetch() ,16);
|
|
return (0xFFFFFFFF&(address_register+offset));
|
|
} break;
|
|
// d8(An,Xn)
|
|
case 0x6: if ((0x0080&allowed_modes)==0) Exception_Handler(4); else
|
|
{ clock_counter=clock_counter+2;
|
|
ea_type=MEMORY;
|
|
address_register=Fetch_Address_Register(EA_register,32);
|
|
ea_extension = BIU_PFQ_Fetch();
|
|
extension_displacement = Sign_Extend( (0x00FF&ea_extension) , 8);
|
|
extension_register = (0x7000&ea_extension)>>12;
|
|
ea_A_bit = ((ea_extension & 0x8000) >> 15);
|
|
ea_L_bit = ((ea_extension & 0x0800) >> 11);
|
|
if (ea_A_bit==1 && ea_L_bit==0) offset=Sign_Extend(Fetch_Address_Register(extension_register,16) ,16); else
|
|
if (ea_A_bit==0 && ea_L_bit==0) offset=Sign_Extend(Fetch_Data_Register(extension_register,16) ,16); else
|
|
if (ea_A_bit==1 && ea_L_bit==1) offset=Fetch_Address_Register(extension_register,32); else
|
|
if (ea_A_bit==0 && ea_L_bit==1) offset=Fetch_Data_Register(extension_register,32);
|
|
return (0xFFFFFFFF&(address_register+offset+extension_displacement));
|
|
} break;
|
|
|
|
case 0x7:
|
|
switch (EA_register)
|
|
{
|
|
case 0x0: if ((0x0040&allowed_modes)==0) Exception_Handler(4); else // Absolute short
|
|
{ ea_type=MEMORY;
|
|
temp_address = Sign_Extend(BIU_PFQ_Fetch(),16);
|
|
return temp_address;
|
|
} break;
|
|
|
|
case 0x1: if ((0x0020&allowed_modes)==0) Exception_Handler(4); else // Absolute long
|
|
{ ea_type=MEMORY;
|
|
temp_address = BIU_PFQ_Fetch();
|
|
temp_address = ( (temp_address<<16) | BIU_PFQ_Fetch() );
|
|
return temp_address;
|
|
} break;
|
|
|
|
case 0x2: if ((0x0010&allowed_modes)==0) Exception_Handler(4); else // x(PC)
|
|
{ ea_type=MEMORY;
|
|
temp_address = (0xFFFFFFFF&(mc68k_pc-2 + Sign_Extend(BIU_PFQ_Fetch(),16))); // This was ok on the Macbook
|
|
//Serial.printf("LEA2 %x \n\r",temp_address);
|
|
return temp_address;
|
|
} break;
|
|
|
|
case 0x3: if ((0x0008&allowed_modes)==0) Exception_Handler(4); else // d8(PC,Xn)
|
|
{ clock_counter=clock_counter+2;
|
|
ea_type=MEMORY;
|
|
original_mc68k_pc = mc68k_pc;
|
|
ea_extension = BIU_PFQ_Fetch();
|
|
extension_displacement = Sign_Extend( (0x00FF&ea_extension) , 8);
|
|
extension_register = (0x7000&ea_extension)>>12;
|
|
ea_A_bit = ((ea_extension & 0x8000) >> 15);
|
|
ea_L_bit = ((ea_extension & 0x0800) >> 11);
|
|
if (ea_A_bit==1 && ea_L_bit==0) offset=Sign_Extend(Fetch_Address_Register(extension_register,16) ,16); else
|
|
if (ea_A_bit==0 && ea_L_bit==0) offset=Sign_Extend(Fetch_Data_Register(extension_register,16) ,16); else
|
|
if (ea_A_bit==1 && ea_L_bit==1) offset=Fetch_Address_Register(extension_register,32); else
|
|
if (ea_A_bit==0 && ea_L_bit==1) offset=Fetch_Data_Register(extension_register,32);
|
|
return (0xFFFFFFFF&(original_mc68k_pc+offset+extension_displacement));
|
|
} break;
|
|
|
|
case 0x4: if ((0x0040&allowed_modes)==0) Exception_Handler(4); else // Immediate
|
|
{ ea_type=IMMEDIATE;
|
|
if (data_size==8) { return (0x00FF&BIU_PFQ_Fetch()); }
|
|
if (data_size==16) { return (0xFFFF&BIU_PFQ_Fetch()); }
|
|
if (data_size==32) { temp_address = BIU_PFQ_Fetch();
|
|
temp_address = ( (temp_address<<16) | BIU_PFQ_Fetch() );
|
|
return temp_address;
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
unsigned long Fetch_EA(unsigned long local_EA , unsigned char local_ea_type)
|
|
{
|
|
if (local_ea_type==ADDRESS_REG && data_size==8 ) return (Fetch_Address_Register(local_EA,8)); else
|
|
if (local_ea_type==ADDRESS_REG && data_size==16) return (Fetch_Address_Register(local_EA,16)); else
|
|
if (local_ea_type==ADDRESS_REG && data_size==32) return (Fetch_Address_Register(local_EA,32)); else
|
|
|
|
if (local_ea_type==DATA_REG && data_size==8 ) return (Fetch_Data_Register(local_EA,8)); else
|
|
if (local_ea_type==DATA_REG && data_size==16) return (Fetch_Data_Register(local_EA,16)); else
|
|
if (local_ea_type==DATA_REG && data_size==32) return (Fetch_Data_Register(local_EA,32)); else
|
|
|
|
if (local_ea_type==MEMORY && data_size==8) return (0xFF&BIU_Read(local_EA , data_size)); else
|
|
if (local_ea_type==MEMORY && data_size==16) return BIU_Read(local_EA , data_size); else
|
|
if (local_ea_type==MEMORY && data_size==32) return BIU_Read_32(local_EA); else
|
|
|
|
if (local_ea_type==IMMEDIATE) { return local_EA; } // Immediate data held in the calculated EA
|
|
|
|
return 0xEEEE;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
void Writeback_EA(unsigned long local_EA , unsigned char local_ea_type , unsigned long writeback_data)
|
|
{
|
|
if (local_ea_type==ADDRESS_REG) { Store_Address_Register(local_EA , writeback_data , data_size); return; }
|
|
if (local_ea_type==DATA_REG) { Store_Data_Register(local_EA , writeback_data , data_size); return; }
|
|
|
|
|
|
if (local_ea_type==MEMORY && data_size==8) { BIU_Write(local_EA , writeback_data , data_size); return; }
|
|
if (local_ea_type==MEMORY && data_size==16) { BIU_Write(local_EA , writeback_data , data_size); return; }
|
|
if (local_ea_type==MEMORY && data_size==32) { BIU_Write_32(local_EA , writeback_data); return; }
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
unsigned long Fetch_Immediate(unsigned char local_size)
|
|
{
|
|
unsigned long temp_data;
|
|
|
|
if (local_size==8) { return (0xFF&BIU_PFQ_Fetch()); }
|
|
if (local_size==16) { return BIU_PFQ_Fetch(); }
|
|
if (local_size==32) { temp_data = BIU_PFQ_Fetch();
|
|
temp_data = ( (temp_data<<16) | BIU_PFQ_Fetch() );
|
|
return temp_data;
|
|
}
|
|
return 0xEEEE;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void Calculate_Flag_N(unsigned long result_data)
|
|
{
|
|
if (data_size==8 && (0x80&result_data)==0) mc68k_flags = (mc68k_flags & 0xFFF7); else
|
|
if (data_size==8 && (0x80&result_data)!=0) mc68k_flags = (mc68k_flags | 0x0008); else
|
|
|
|
if (data_size==16 && (0x8000&result_data)==0) mc68k_flags = (mc68k_flags & 0xFFF7); else
|
|
if (data_size==16 && (0x8000&result_data)!=0) mc68k_flags = (mc68k_flags | 0x0008); else
|
|
|
|
if (data_size==32 && (0x80000000&result_data)==0) mc68k_flags = (mc68k_flags & 0xFFF7); else
|
|
if (data_size==32 && (0x80000000&result_data)!=0) mc68k_flags = (mc68k_flags | 0x0008);
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void Calculate_Flag_Z(unsigned long result_data , unsigned char clear_only)
|
|
{
|
|
|
|
if (data_size==8 && (0xFF&result_data)!=0) mc68k_flags = (mc68k_flags & 0xFFFB); else
|
|
if (data_size==8 && (0xFF&result_data)==0 && clear_only==FALSE) mc68k_flags = (mc68k_flags | 0x0004); else
|
|
|
|
if (data_size==16 && (0xFFFF&result_data)!=0) mc68k_flags = (mc68k_flags & 0xFFFB); else
|
|
if (data_size==16 && (0xFFFF&result_data)==0&& clear_only==FALSE) mc68k_flags = (mc68k_flags | 0x0004); else
|
|
|
|
if (data_size==32 && (0xFFFFFFFF&result_data)!=0) mc68k_flags = (mc68k_flags & 0xFFFB); else
|
|
if (data_size==32 && (0xFFFFFFFF&result_data)==0 && clear_only==FALSE) mc68k_flags = (mc68k_flags | 0x0004);
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_MOVE()
|
|
{
|
|
data_size = DATA_SIZE_TYPE_B; // Get the data size from the opcode bits[13:12]
|
|
|
|
source_ea = Calculate_EA(0x3FFC); // Calculate the Source EA, checking supported modes
|
|
source_ea_type = ea_type;
|
|
|
|
first_opcode = (0x0FC0&first_opcode); // Re-arrange the second EA bit fields to the usual locations for the MOVE instruction
|
|
first_opcode = ( ((0x01C0&first_opcode)>>3) | ((0x0E00&first_opcode)>>9) );
|
|
|
|
destination_ea = Calculate_EA(0x3FE0); // Calculate the Destination EA, checking supported modes
|
|
destination_ea_type = ea_type;
|
|
|
|
|
|
EA_Data = Fetch_EA(source_ea , source_ea_type); // Fetch the Source EA operand
|
|
|
|
if ( (destination_ea_type==ADDRESS_REG) && data_size==16) { Writeback_EA(destination_ea , destination_ea_type ,(Sign_Extend(EA_Data ,16)) ); } // Write-back to Destination EA
|
|
else { Writeback_EA(destination_ea , destination_ea_type , EA_Data ); }
|
|
|
|
|
|
if (destination_ea_type != ADDRESS_REG) // Don't update flags for MOVEA
|
|
{
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Always clear V, C Flags
|
|
Calculate_Flag_N(EA_Data); // Calculate the N Flag
|
|
Calculate_Flag_Z(EA_Data , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
}
|
|
clock_counter=0;
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_MOVE_TO_CCR()
|
|
{
|
|
clock_counter=clock_counter+8;
|
|
data_size = 8;
|
|
source_ea = Calculate_EA(0x2FFC); // Calculate the Source EA, checking supported modes
|
|
EA_Data = Fetch_EA(source_ea , ea_type); // Fetch the Source EA operand
|
|
mc68k_flags = ( (0xFF00&mc68k_flags) | (0x001F&EA_Data) ); // Update the CCR Flags
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_MOVE_TO_SR()
|
|
{
|
|
if (mc68k_flag_S==0x0) { Exception_Handler(8); } // Verify that supervisor privilege is set
|
|
else
|
|
{
|
|
clock_counter=clock_counter+4;
|
|
data_size = 16;
|
|
source_ea = Calculate_EA(0x2FFC); // Calculate the Source EA, checking supported modes
|
|
EA_Data = Fetch_EA(source_ea , ea_type); // Fetch the Source EA operand
|
|
mc68k_flags = (EA_Data); // Update the SR Flags
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_MOVE_FROM_SR()
|
|
{
|
|
clock_counter=clock_counter+2;
|
|
data_size = 16;
|
|
calculated_EA = Calculate_EA(0x2FE0); // Calculate the Source EA, checking supported modes
|
|
EA_Data = Fetch_EA(calculated_EA , ea_type); // Unnecessary fetch the EA operand ** Unoptimized 68000 **
|
|
Writeback_EA(calculated_EA , ea_type ,mc68k_flags); // Write-back to the Destination EA
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_MOVE_USP()
|
|
{
|
|
if (mc68k_flag_S==0x0) { Exception_Handler(8); } // Verify that supervisor privilege is set
|
|
else
|
|
{
|
|
data_size = 32;
|
|
EA_register =(0x0007&first_opcode);
|
|
|
|
if ((0x8&first_opcode)==0) { m68k_address_reg[7] = Fetch_Address_Register(EA_register,32); } else // Address Register --> USP
|
|
{ Store_Address_Register(EA_register , m68k_address_reg[7] , 32); } // USP --> Address Register
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_JMP()
|
|
{
|
|
calculated_EA = Calculate_EA(0x09F8); // Calculate the EA, checking supported modes
|
|
BIU_Jump(calculated_EA); // Jump to the new PC
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_JSR()
|
|
{
|
|
calculated_EA = Calculate_EA(0x09F8); // Calculate the EA, checking supported modes
|
|
Push(mc68k_pc&0xFFFF); // Stack the lower PC
|
|
Push(mc68k_pc>>16); // Stack the upper PC
|
|
BIU_Jump(calculated_EA); // Jump to the new PC
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_BSR()
|
|
{
|
|
unsigned long opcode_pc;
|
|
unsigned long displacement;
|
|
|
|
clock_counter=clock_counter+2;
|
|
displacement = (0x00FF&first_opcode); // Isolate the displacement field of the opcode
|
|
opcode_pc = mc68k_pc ; // Store the PC of the initial opcode
|
|
|
|
if (displacement==0) { displacement=Sign_Extend(BIU_PFQ_Fetch() , 16); } // Sign extend the 16-bit displacement held in the next opcode word
|
|
else { displacement=Sign_Extend(displacement , 8); } // Sign extend the 8-bit displacement held in the initial opcode
|
|
|
|
Push(mc68k_pc&0xFFFF); // Stack the lower PC of address of the next opcode
|
|
Push(mc68k_pc>>16); // Stack the upper PC of address of the next opcode
|
|
BIU_Jump(opcode_pc + displacement); // Jump to the new PC calculated using the address of first byte of the opcode
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_RTS()
|
|
{
|
|
mc68k_pc = Pop()<<16; // Pop the upper PC
|
|
mc68k_pc = mc68k_pc | Pop(); // Pop the lower PC
|
|
BIU_Jump(mc68k_pc); // Jump to the new PC
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_RTR()
|
|
{
|
|
clock_counter=clock_counter+16;
|
|
mc68k_flags = ( (0xFFE0&mc68k_flags) | (0x001F&Pop()) ); // Update the CCR Flags
|
|
mc68k_pc = Pop()<<16; // Pop the upper PC
|
|
mc68k_pc = mc68k_pc | Pop(); // Pop the lower PC
|
|
BIU_Jump(mc68k_pc); // Jump to the new PC
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_BCC()
|
|
{
|
|
unsigned long opcode_pc;
|
|
unsigned long displacement;
|
|
|
|
displacement = (0x00FF&first_opcode); // Isolate the displacement field of the opcode
|
|
opcode_pc = mc68k_pc ; // Store the PC of the initial opcode
|
|
|
|
if (displacement==0) { displacement=Sign_Extend(BIU_PFQ_Fetch() , 16); } // Sign extend the 16-bit displacement held in the next opcode word
|
|
else { displacement=Sign_Extend(displacement , 8); } // Sign extend the 8-bit displacement held in the initial opcode
|
|
|
|
BIU_PFQ_add_word(); // To match 68000
|
|
|
|
if (Test_Condition(first_opcode)==TRUE) { clock_counter=clock_counter+2; BIU_Jump(opcode_pc + displacement); } // Jump to the new PC
|
|
else { clock_counter=clock_counter+4; return; }
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_SCC()
|
|
{
|
|
data_size = 8;
|
|
calculated_EA = Calculate_EA(0x2FE0); // Calculate the EA, checking supported modes
|
|
EA_Data = Fetch_EA(calculated_EA , ea_type); // Unnecessary fetch the EA operand ** Unoptimized 68000 **
|
|
|
|
if (Test_Condition(first_opcode)==TRUE) { EA_Data=0x000000FF; } // Condition TRUE, so set the byte to 0xFF
|
|
else { EA_Data=0xFFFFFF00; } // Condition FALSE, so clear the byte to 0
|
|
|
|
Writeback_EA(calculated_EA , ea_type ,EA_Data); // Write-back to the EA
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_dBCC()
|
|
{
|
|
unsigned long opcode_pc;
|
|
unsigned long displacement;
|
|
unsigned int counter;
|
|
|
|
reg_num = (0x0007&first_opcode); // Isolate the register number from the opcode
|
|
opcode_pc = mc68k_pc; // Store the PC of the initial opcode
|
|
|
|
displacement=Sign_Extend(BIU_PFQ_Fetch() , 16); // Fetch and sign-extend the 16-bit displacement from the second opcode
|
|
|
|
counter = Fetch_Data_Register(reg_num,16); // Fetch the Loop counter value from the register - just lower 16-bits
|
|
|
|
if ( Test_Condition(first_opcode)==FALSE )
|
|
{
|
|
counter = counter - 1;
|
|
Store_Data_Register(reg_num , counter , 16); // Write-back the counter value to the register
|
|
|
|
if ((0x0000FFFF&counter)==0xFFFF) { clock_counter=clock_counter+2; return; } // When the counter equals (-1), continue to next opcode, else jump to the new PC
|
|
else { clock_counter=0; BIU_Jump(opcode_pc + displacement); return; }
|
|
|
|
}
|
|
else
|
|
{
|
|
clock_counter=clock_counter+2;
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_LEA()
|
|
{
|
|
|
|
data_size = 32;
|
|
calculated_EA = Calculate_EA(0x09F8); // Calculate the EA, checking supported modes
|
|
reg_num = (0x0E00&first_opcode)>>9; // Isolate the register number from the opcode
|
|
Store_Address_Register(reg_num , calculated_EA , 32); // Write-back the EA value to the register
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_PEA()
|
|
{
|
|
data_size = 32;
|
|
calculated_EA = Calculate_EA(0x09F8); // Calculate the EA, checking supported modes
|
|
Push(calculated_EA&0xFFFF); // Stack the lower portion of the EA
|
|
Push(calculated_EA>>16); // Stack the upper portion of the EA
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_CHK()
|
|
{
|
|
signed short int reg_data;
|
|
|
|
clock_counter=6;
|
|
data_size = 16;
|
|
calculated_EA = Calculate_EA(0x02FFC); // Calculate the EA, checking supported modes
|
|
EA_Data = Fetch_EA(calculated_EA , ea_type); // Fetch the EA operand
|
|
|
|
reg_num = (0x0E00&first_opcode)>>9; // Isolate the register number from the opcode
|
|
reg_data = Fetch_Data_Register(reg_num,16); // Fetch the lower 16-bits of the Data Register
|
|
|
|
if ( (0x8000®_data) != 0) // Is number negative?
|
|
{
|
|
mc68k_flags = mc68k_flags | 0x08; // Set the N flag
|
|
Exception_Handler(6);
|
|
return;
|
|
}
|
|
else if ( (signed short int)reg_data > (signed short int)EA_Data )
|
|
{
|
|
mc68k_flags = mc68k_flags & 0xFFF7; // Clear the N flag
|
|
Exception_Handler(6);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_TRAPV()
|
|
{
|
|
clock_counter=2;
|
|
if (mc68k_flag_V==1) { Exception_Handler(7); return; }
|
|
else { return; }
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_TRAP()
|
|
{
|
|
clock_counter=6;
|
|
Exception_Handler( (0x000F&first_opcode) + 32 ); // Isolate the register number from the opcode and add 32 to create the vector number
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_LINK()
|
|
{
|
|
signed long reg_data;
|
|
|
|
reg_num = (0x0007&first_opcode); // Isolate the register number from the opcode
|
|
reg_data = Fetch_Address_Register(reg_num,32); // Fetch the Address Register
|
|
Push(reg_data&0xFFFF); // Stack the lower portion of the Address Register
|
|
Push(reg_data>>16); // Stack the upper portion of the Address Register
|
|
|
|
if (mc68k_flag_S==1)
|
|
{
|
|
Store_Address_Register(reg_num, m68k_a7_S , 32); // Copy the active Stack Pointer to the selected Address Register
|
|
m68k_a7_S = m68k_a7_S + Sign_Extend(BIU_PFQ_Fetch() ,16);
|
|
}
|
|
else
|
|
{
|
|
Store_Address_Register(reg_num, m68k_address_reg[7] , 32);
|
|
m68k_address_reg[7] = m68k_address_reg[7] + Sign_Extend(BIU_PFQ_Fetch() ,16);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_UNLK()
|
|
{
|
|
unsigned long reg_data;
|
|
|
|
reg_num = (0x0007&first_opcode); // Isolate the register number from the opcode
|
|
reg_data = Fetch_Address_Register(reg_num,32); // Fetch the Address Register
|
|
|
|
if (mc68k_flag_S==1) { m68k_a7_S = reg_data; } // Copy Address contents to the current Stack Pointer
|
|
else { m68k_address_reg[7] = reg_data; }
|
|
|
|
reg_data = Pop()<<16; // Pop the upper Address Register
|
|
reg_data = reg_data | Pop(); // Pop the lower Address Register
|
|
Store_Address_Register(reg_num, reg_data , 32); // Write-back the stacked address to the Address Register
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_RTE()
|
|
{
|
|
uint16_t temp_flags;
|
|
|
|
if (mc68k_flag_S==0x0) { Exception_Handler(8); } // Verify that supervisor privilege is set
|
|
else
|
|
{
|
|
//Update_System_Flags(Pop()); // Pop the SR Flags
|
|
//mc68k_pc = Pop()<<16; // Pop the upper PC
|
|
//mc68k_pc = mc68k_pc | Pop(); // Pop the lower PC
|
|
//BIU_Jump(mc68k_pc); // Jump to the new PC
|
|
|
|
temp_flags = Pop();
|
|
mc68k_pc = Pop()<<16;
|
|
mc68k_pc = mc68k_pc | Pop();
|
|
mc68k_flags = (temp_flags);
|
|
BIU_Jump(mc68k_pc);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_RESET()
|
|
{
|
|
if (mc68k_flag_S==0x0) { Exception_Handler(8); } // Verify that supervisor privilege is set
|
|
// else { BIU_Force_Reset(); }
|
|
else { Reset_routine(); }
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_STOP()
|
|
{
|
|
if (mc68k_flag_S==0x0) { Exception_Handler(8); } // Verify that supervisor privilege is set
|
|
else
|
|
{
|
|
clock_counter=4;
|
|
mc68k_flags = (BIU_PFQ_Fetch()); // Fetch the SR Flags
|
|
|
|
while ( gpio6_reset_n!=0 && gpio6_ipl==0 && mc68k_flag_T==0) {
|
|
gpio6_ipl = 0x7 & (0x7 ^ ((gpio6_data & IPL2_0_BITs)>>16 )); // Invert the IPL bits which are active low on the pins
|
|
gpio6_reset_n = GPIO6_DR & RESET_n_BIT;
|
|
} // Proceed if Trace is active, or RESET/Interrupt occurs
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_SWAP()
|
|
{
|
|
unsigned long reg_data;
|
|
|
|
clock_counter=4;
|
|
data_size = 32;
|
|
reg_num = (0x0007&first_opcode); // Isolate the register number from the opcode
|
|
|
|
reg_data = Fetch_Data_Register(reg_num,32); // Swap the upper and lower words of the register, then write it back
|
|
reg_data = (reg_data<<16 | reg_data>>16);
|
|
Store_Data_Register(reg_num , reg_data , 32);
|
|
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Always clear V, C Flags
|
|
Calculate_Flag_N(reg_data); // Calculate the N Flag
|
|
Calculate_Flag_Z(reg_data , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_EXT()
|
|
{
|
|
unsigned long reg_data;
|
|
|
|
reg_num = (0x0007&first_opcode); // Isolate the register number from the opcode
|
|
|
|
if ( ((0x00C0&first_opcode)>>6) == 2)
|
|
{
|
|
reg_data = Sign_Extend(Fetch_Data_Register(reg_num,8) ,8);
|
|
Store_Data_Register(reg_num , reg_data , 16);
|
|
data_size = 16; // Set size for flag calculation
|
|
}
|
|
else
|
|
{
|
|
reg_data = Sign_Extend(Fetch_Data_Register(reg_num,16) ,16);
|
|
Store_Data_Register(reg_num , reg_data , 32);
|
|
data_size = 32; // Set size for flag calculation
|
|
}
|
|
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Always clear V, C Flags
|
|
Calculate_Flag_N(reg_data); // Calculate the N Flag
|
|
Calculate_Flag_Z(reg_data , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_MOVEQ()
|
|
{
|
|
unsigned long reg_data;
|
|
|
|
reg_num = (0x0E00&first_opcode)>>9; // Isolate the register number from the opcode
|
|
|
|
reg_data = Sign_Extend(first_opcode ,8); // Sign-extend the data held in the opcode and write-back to selected register
|
|
Store_Data_Register(reg_num , reg_data , 32);
|
|
|
|
data_size = 32; // Set size for flag calculation
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Always clear V, C Flags
|
|
Calculate_Flag_N(reg_data); // Calculate the N Flag
|
|
Calculate_Flag_Z(reg_data , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_MOVEM()
|
|
{
|
|
unsigned short increment_size;
|
|
unsigned int reg_list;
|
|
|
|
data_size = DATA_SIZE_TYPE_C; // Get the data size from the opcode bit[6]
|
|
increment_size = data_size>>3; // increment_size is +2 for Word, +4 for Long
|
|
|
|
if ( ((0x0400&first_opcode)>>10) == 1) // ** Memory to Registers **
|
|
{
|
|
reg_list = BIU_PFQ_Fetch(); // Get the Register_list from the second opcode word
|
|
calculated_EA=Calculate_EA(0x0DF8);
|
|
BIU_PFQ_add_word();
|
|
|
|
if ( (0x0001®_list)!=0) { Store_Data_Register (0 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // D0
|
|
if ( (0x0002®_list)!=0) { Store_Data_Register (1 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // D1
|
|
if ( (0x0004®_list)!=0) { Store_Data_Register (2 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // D2
|
|
if ( (0x0008®_list)!=0) { Store_Data_Register (3 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // D3
|
|
if ( (0x0010®_list)!=0) { Store_Data_Register (4 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // D4
|
|
if ( (0x0020®_list)!=0) { Store_Data_Register (5 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // D5
|
|
if ( (0x0040®_list)!=0) { Store_Data_Register (6 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // D6
|
|
if ( (0x0080®_list)!=0) { Store_Data_Register (7 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // D7
|
|
if ( (0x0100®_list)!=0) { Store_Address_Register(0 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // A0
|
|
if ( (0x0200®_list)!=0) { Store_Address_Register(1 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // A1
|
|
if ( (0x0400®_list)!=0) { Store_Address_Register(2 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // A2
|
|
if ( (0x0800®_list)!=0) { Store_Address_Register(3 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // A3
|
|
if ( (0x1000®_list)!=0) { Store_Address_Register(4 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // A4
|
|
if ( (0x2000®_list)!=0) { Store_Address_Register(5 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // A5
|
|
if ( (0x4000®_list)!=0) { Store_Address_Register(6 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // A6
|
|
if ( (0x8000®_list)!=0) { Store_Address_Register(7 , Sign_Extend(Fetch_EA(calculated_EA , ea_type) ,data_size) , 32); calculated_EA=calculated_EA+increment_size; } // A7
|
|
|
|
data_size = 16;
|
|
//immediate = Fetch_EA(calculated_EA , ea_type); // Extra fetch due to 68000 anomaly
|
|
|
|
if ( ((0x0038&first_opcode)>>3) == 0x3 ) Store_Address_Register(EA_register, calculated_EA , 32); // Write-back the address register for (An)+ Mode
|
|
}
|
|
|
|
|
|
else if ( ((0x0400&first_opcode)>>10) == 0 && ((0x0038&first_opcode)>>3) == 0x4 ) // ** Registers to Memory -(An) Addressing Mode **
|
|
{
|
|
reg_list = BIU_PFQ_Fetch(); // Get the Register_list from the second opcode word
|
|
calculated_EA = Calculate_EA(0x0BE0) + increment_size; // Get the Address but adjust so decrementing can start fresh below
|
|
Store_Address_Register(EA_register, (calculated_EA) , 32); // Write-back the address register to the initial value
|
|
|
|
if ( (0x0001®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(7,32) ); } // A7
|
|
if ( (0x0002®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(6,32) ); } // A6
|
|
if ( (0x0004®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(5,32) ); } // A5
|
|
if ( (0x0008®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(4,32) ); } // A4
|
|
if ( (0x0010®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(3,32) ); } // A3
|
|
if ( (0x0020®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(2,32) ); } // A2
|
|
if ( (0x0040®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(1,32) ); } // A1
|
|
if ( (0x0080®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(0,32) ); } // A0
|
|
if ( (0x0100®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (7,32) ); } // D7
|
|
if ( (0x0200®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (6,32) ); } // D6
|
|
if ( (0x0400®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (5,32) ); } // D5
|
|
if ( (0x0800®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (4,32) ); } // D4
|
|
if ( (0x1000®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (3,32) ); } // D3
|
|
if ( (0x2000®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (2,32) ); } // D2
|
|
if ( (0x4000®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (1,32) ); } // D1
|
|
if ( (0x8000®_list)!=0) { calculated_EA=calculated_EA-increment_size; Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (0,32) ); } // D0
|
|
|
|
Store_Address_Register(EA_register, calculated_EA , 32); // Write-back the address register
|
|
}
|
|
|
|
|
|
else if ( ((0x0400&first_opcode)>>10) == 0 && ((0x0038&first_opcode)>>3) != 0x4 ) // ** Registers to Memory All except -(An) Addressing Mode **
|
|
{
|
|
reg_list = BIU_PFQ_Fetch(); // Get the Register_list from the second opcode word
|
|
calculated_EA=Calculate_EA(0x0BE0);
|
|
|
|
if ( (0x0001®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (0,32) ); calculated_EA=calculated_EA+increment_size; } // D0
|
|
if ( (0x0002®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (1,32) ); calculated_EA=calculated_EA+increment_size; } // D1
|
|
if ( (0x0004®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (2,32) ); calculated_EA=calculated_EA+increment_size; } // D2
|
|
if ( (0x0008®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (3,32) ); calculated_EA=calculated_EA+increment_size; } // D3
|
|
if ( (0x0010®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (4,32) ); calculated_EA=calculated_EA+increment_size; } // D4
|
|
if ( (0x0020®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (5,32) ); calculated_EA=calculated_EA+increment_size; } // D5
|
|
if ( (0x0040®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (6,32) ); calculated_EA=calculated_EA+increment_size; } // D6
|
|
if ( (0x0080®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Data_Register (7,32) ); calculated_EA=calculated_EA+increment_size; } // D7
|
|
if ( (0x0100®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(0,32) ); calculated_EA=calculated_EA+increment_size; } // A0
|
|
if ( (0x0200®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(1,32) ); calculated_EA=calculated_EA+increment_size; } // A1
|
|
if ( (0x0400®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(2,32) ); calculated_EA=calculated_EA+increment_size; } // A2
|
|
if ( (0x0800®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(3,32) ); calculated_EA=calculated_EA+increment_size; } // A3
|
|
if ( (0x1000®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(4,32) ); calculated_EA=calculated_EA+increment_size; } // A4
|
|
if ( (0x2000®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(5,32) ); calculated_EA=calculated_EA+increment_size; } // A5
|
|
if ( (0x4000®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(6,32) ); calculated_EA=calculated_EA+increment_size; } // A6
|
|
if ( (0x8000®_list)!=0) { Writeback_EA(calculated_EA , ea_type , Fetch_Address_Register(7,32) ); calculated_EA=calculated_EA+increment_size; } // A7
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_TAS()
|
|
{
|
|
data_size = 8;
|
|
calculated_EA = Calculate_EA(0x2FE0); // Calculate the EA, checking supported modes
|
|
|
|
// BIU_RMW(TRUE); // Signal the BIU to perform an atomic R-M-W Cycle
|
|
|
|
EA_Data = Fetch_EA(calculated_EA , ea_type); // Fetch the data
|
|
Writeback_EA(calculated_EA , ea_type , (0x80|EA_Data)); // Write-back the data with bit[7] set to 1
|
|
|
|
//BIU_RMW(FALSE); // Debounce R-M-W Cycle
|
|
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Always clear V, C Flags
|
|
Calculate_Flag_N(EA_Data); // Calculate the N Flag
|
|
Calculate_Flag_Z(EA_Data , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_TST()
|
|
{
|
|
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
calculated_EA = Calculate_EA(0x2FE0); // Calculate the EA, checking supported modes
|
|
|
|
EA_Data = Fetch_EA(calculated_EA , ea_type); // Fetch the data
|
|
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Always clear V, C Flags
|
|
Calculate_Flag_N(EA_Data); // Calculate the N Flag
|
|
Calculate_Flag_Z(EA_Data , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
|
|
return;
|
|
}
|
|
|
|
// op_type 0=ADD 1=SUB
|
|
// ----------------------------------------------------------------------
|
|
void Calculate_Flags_C(unsigned long long operand0 , unsigned long long operand1 , unsigned char op_type)
|
|
{
|
|
unsigned long long carry=0;
|
|
|
|
if (op_type==0)
|
|
{
|
|
if (data_size==8) { carry = ( ((operand0&0x000000FF)+(operand1&0x000000FF)) & 0x00000100 ); }
|
|
else if (data_size==16) { carry = ( ((operand0&0x0000FFFF)+(operand1&0x0000FFFF)) & 0x00010000 ); }
|
|
else if (data_size==32) { carry = ( ((operand0&0xFFFFFFFF)+(operand1&0xFFFFFFFF)) & 0x100000000 ); }
|
|
}
|
|
else
|
|
{
|
|
if (data_size==8) { carry = ( ((operand0&0x000000FF)-(operand1&0x000000FF)) & 0x00000100 ); }
|
|
else if (data_size==16) { carry = ( ((operand0&0x0000FFFF)-(operand1&0x0000FFFF)) & 0x00010000 ); }
|
|
else if (data_size==32) { carry = ( ((operand0&0xFFFFFFFF)-(operand1&0xFFFFFFFF)) & 0x100000000 ); }
|
|
}
|
|
|
|
if (carry!=0) { mc68k_flags = ( mc68k_flags | 0x0001); } //Set C Flag
|
|
return;
|
|
}
|
|
|
|
|
|
void Calculate_Flags_V(unsigned long operand0 , unsigned long operand1 , unsigned long result , unsigned char op_size , unsigned char op_type)
|
|
{
|
|
unsigned char overflow=0;
|
|
|
|
if (op_size==8) { operand0 = (operand0&0x00000080); operand1 = (operand1&0x00000080); result = (result&0x00000080); }
|
|
else if (op_size==16) { operand0 = (operand0&0x00008000); operand1 = (operand1&0x00008000); result = (result&0x00008000); }
|
|
else if (op_size==32) { operand0 = (operand0&0x80000000); operand1 = (operand1&0x80000000); result = (result&0x80000000); }
|
|
|
|
if (op_type==0 )
|
|
{
|
|
if (operand0==0 && operand1==0 && result!=0) { overflow=1; } //Set V Flag for ADD
|
|
else if (operand0!=0 && operand1!=0 && result==0) { overflow=1; }
|
|
}
|
|
else
|
|
{
|
|
if (operand0==0 && operand1!=0 && result!=0) { overflow=1; } //Set V Flag for SUB
|
|
else if (operand0!=0 && operand1==0 && result==0) { overflow=1; }
|
|
}
|
|
|
|
if (overflow==1) { mc68k_flags = ( mc68k_flags | 0x0002); } // Set V Flag
|
|
else { mc68k_flags = ( mc68k_flags & 0xFFFD); } // Clear V Flag
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
// op_type 1=NOT 2=NEG 3=NEGX 4=CLR
|
|
// ----------------------------------------------------------------------
|
|
void op_NEGS(unsigned char op_type)
|
|
{
|
|
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
calculated_EA = Calculate_EA(0x2FE0); // Calculate the EA, checking supported modes
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Pre-clear V, C Flags
|
|
|
|
EA_Data = Fetch_EA(calculated_EA , ea_type); // Fetch the data
|
|
|
|
if (op_type==1) { EA_Data=(~EA_Data); // NOT
|
|
Calculate_Flag_Z(EA_Data , FALSE);
|
|
} else
|
|
|
|
if (op_type==2) { Calculate_Flags_C(0 , EA_Data , 1); // NEG
|
|
Calculate_Flags_V(0 , EA_Data , -EA_Data , data_size , 1);
|
|
EA_Data= -EA_Data;
|
|
Calculate_Flag_Z(EA_Data , FALSE);
|
|
if (EA_Data==0) { mc68k_flags=(mc68k_flags & 0xFFEE); } else // Set/Clear X and C Flags
|
|
{ mc68k_flags=(mc68k_flags | 0x0011); }
|
|
} else
|
|
|
|
if (op_type==3) { Calculate_Flags_C(0 , EA_Data , 1); // NEGX ** Z Flag - Clear_only = TRUE
|
|
Calculate_Flags_V(0 , EA_Data , (0-EA_Data) , data_size , 1);
|
|
EA_Data= -EA_Data;
|
|
Calculate_Flags_C(EA_Data , mc68k_flag_X , 1);
|
|
Calculate_Flags_V(EA_Data , mc68k_flag_X , (EA_Data+mc68k_flag_X) , data_size , 1);
|
|
EA_Data=(EA_Data - mc68k_flag_X);
|
|
Calculate_Flag_Z(EA_Data , TRUE);
|
|
if (mc68k_flag_C != 0) { mc68k_flags=(mc68k_flags | 0x0010); } else // Copy C flag to X flag
|
|
{ mc68k_flags=(mc68k_flags & 0xFFEF); }
|
|
} else
|
|
|
|
if (op_type==4) { EA_Data=(0x0); // CLR
|
|
Calculate_Flag_Z(EA_Data , FALSE);
|
|
}
|
|
|
|
Writeback_EA(calculated_EA,ea_type,EA_Data);
|
|
|
|
Calculate_Flag_N(EA_Data);
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_EXG()
|
|
{
|
|
unsigned char regX;
|
|
unsigned char regY;
|
|
unsigned long tempX;
|
|
unsigned long tempY;
|
|
|
|
clock_counter=clock_counter+2;
|
|
|
|
regX = (0x0E00&first_opcode)>>9; // Isolate register numbers from the opcode
|
|
regY = (0x0007&first_opcode);
|
|
|
|
if ( (0x01F8&first_opcode) == 0x0140) { tempX = Fetch_Data_Register(regX,32); // Exchange the registers
|
|
tempY = Fetch_Data_Register(regY,32);
|
|
Store_Data_Register(regX , tempY , 32);
|
|
Store_Data_Register(regY , tempX , 32);
|
|
}
|
|
else if ( (0x01F8&first_opcode) == 0x0148) { tempX = Fetch_Address_Register(regX,32);
|
|
tempY = Fetch_Address_Register(regY,32);
|
|
Store_Address_Register(regX , tempY , 32);
|
|
Store_Address_Register(regY , tempX , 32);
|
|
}
|
|
else if ( (0x01F8&first_opcode) == 0x0188) { tempX = Fetch_Data_Register(regX,32);
|
|
tempY = Fetch_Address_Register(regY,32);
|
|
Store_Data_Register(regX , tempY , 32);
|
|
Store_Address_Register(regY , tempX , 32);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
// op_type 00=BSET_Dynamic 10=BCLR_Dynamic 20=BCHG_Dynamic 30=BTST_Dynamic
|
|
// 01=BSET_Static 11=BCLR_Static 21=BCHG_Static 31=BTST_Static
|
|
// ------------------------------------------------------------------------------
|
|
void op_BMOD(unsigned char op_type)
|
|
{
|
|
unsigned long bit_num;
|
|
|
|
clock_counter=clock_counter+4;
|
|
|
|
if ( (0x0F&op_type)==0x0) // ** Bit-number Dynamic **
|
|
{
|
|
reg_num = (0x0E00&first_opcode)>>9; // Isolate the register number from the opcode
|
|
|
|
data_size = 8; // Force EA Calculation to use BYTE mode so pre-decrement and post-increment address modifications as well as immediate fetching are correct
|
|
if ((0xF0&op_type)==0x30) calculated_EA = Calculate_EA(0x2FFC); else calculated_EA = Calculate_EA(0x2FE0); // BTST allowed EA types different from rest
|
|
|
|
if (ea_type==MEMORY) { bit_num = (0x7&Fetch_Data_Register(reg_num,8)); // Isolate a byte's worth of bit addressing
|
|
EA_Data = (0xFF&Fetch_EA(calculated_EA , ea_type)); // Fetch the byte data from the Memory EA
|
|
}
|
|
else { bit_num = (0x1F&Fetch_Data_Register(reg_num,8)); // Isolate 32-bits worth of bit addressing
|
|
data_size = 32; // Force data size to 32-bit for non-memory locations
|
|
clock_counter=clock_counter+2;
|
|
EA_Data = (Fetch_EA(calculated_EA , ea_type)); // Fetch the register or immediate data
|
|
}
|
|
}
|
|
|
|
else // ** Bit-number Static **
|
|
{
|
|
bit_num = Fetch_Immediate(8); // Fetch the Bit Number field first
|
|
|
|
data_size = 8; // Force EA Calculation to use BYTE mode so pre-decrement and post-increment address modifications as well as immediate fetching are correct
|
|
if ((0xF0&op_type)==0x30) calculated_EA = Calculate_EA(0x2FF8); else calculated_EA = Calculate_EA(0x2FE0); // BTST allowed EA types different from rest
|
|
|
|
if (ea_type==MEMORY) { bit_num = (0x7&bit_num); // Isolate a byte's worth of bit addressing from the second opcode
|
|
EA_Data = (0xFF&Fetch_EA(calculated_EA , ea_type)); // Fetch the byte data from the Memory EA
|
|
}
|
|
else { bit_num = (0x1F&bit_num); // Isolate 32-bits worth of bit addressing from the second opcode
|
|
data_size = 32; // Force data size to 32-bit for non-memory locations
|
|
clock_counter=clock_counter+2;
|
|
EA_Data = (Fetch_EA(calculated_EA , ea_type)); // Fetch the register or immediate data
|
|
|
|
}
|
|
}
|
|
|
|
bit_num = 0x1<<bit_num; // Convert encoded bit number to a one-bit-active vector
|
|
if ( (EA_Data & bit_num) == 0) { mc68k_flags = ( mc68k_flags | 0x0004); } // Calculate Z Flag
|
|
else { mc68k_flags = ( mc68k_flags & 0xFFFB); }
|
|
|
|
|
|
if ( (0xF0&op_type)==0x00) { EA_Data = (EA_Data | bit_num); Writeback_EA(calculated_EA , ea_type , EA_Data); } else // BSET - Set the selected bit in the EA's Data
|
|
if ( (0xF0&op_type)==0x10) { EA_Data = (EA_Data & ~bit_num); Writeback_EA(calculated_EA , ea_type , EA_Data); } else // BCLR - Clear the selected bit in the EA's Data
|
|
if ( (0xF0&op_type)==0x20) { EA_Data = (EA_Data ^ bit_num); Writeback_EA(calculated_EA , ea_type , EA_Data); } // BCHG - Change the selected bit in the EA's Data
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// op_type 1=ASL 2=LSL
|
|
// ----------------------------------------------------------------------
|
|
void op_xSL(unsigned char dst_is_register , unsigned char op_type)
|
|
{
|
|
unsigned long data;
|
|
unsigned char shift_count;
|
|
|
|
mc68k_flags=(mc68k_flags&0xFFFD); // Pre-clear the V flag
|
|
|
|
if (dst_is_register==1) { if (data_size==32) {clock_counter=clock_counter+4;} else {clock_counter=clock_counter+2;}
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
immediate = (0x0E00&first_opcode)>>9; // Isolate the Immediate number from the opcode
|
|
reg_num = (0x0007&first_opcode); // Isolate the register number from the opcode
|
|
data = Fetch_Data_Register(reg_num,data_size); // Fetch the register we want to shift
|
|
if ((0x0020&first_opcode) == 0) // T=0 for Immediate field contains the shift_count T=1 for shift_count contained in a register - Modulo-64
|
|
{ if(immediate==0) shift_count=8; else shift_count = immediate;
|
|
}
|
|
else
|
|
{ shift_count = (0x3F&Fetch_Data_Register(immediate,8));
|
|
}
|
|
}
|
|
|
|
else { clock_counter=clock_counter-2;
|
|
data_size = 16; // Size is always 16 for memory
|
|
shift_count = 1; // Shift count is always 1 for memory
|
|
calculated_EA = Calculate_EA(0x0FE0); // Calculate the EA, checking supported modes
|
|
data = (Fetch_EA(calculated_EA , ea_type)); // Fetch the word data we want to shift from the EA
|
|
}
|
|
|
|
while (shift_count!=0)
|
|
{
|
|
clock_counter=clock_counter+2;
|
|
if (data_size==8) { if( (0x00000080&data)==0) mc68k_flags=(mc68k_flags&0xFFEE); else mc68k_flags=(mc68k_flags|0x0011); } // Copy data[MSB] to the X and C flags
|
|
if (data_size==16) { if( (0x00008000&data)==0) mc68k_flags=(mc68k_flags&0xFFEE); else mc68k_flags=(mc68k_flags|0x0011); }
|
|
if (data_size==32) { if( (0x80000000&data)==0) mc68k_flags=(mc68k_flags&0xFFEE); else mc68k_flags=(mc68k_flags|0x0011); }
|
|
|
|
if (data_size==8) { if( (0x000000C0&data)==0x00000080 || (0x000000C0&data)==0x00000040 ) mc68k_flags=(mc68k_flags|0x0002); } // Set V if the MSB ever changes
|
|
if (data_size==16) { if( (0x0000C000&data)==0x00008000 || (0x0000C000&data)==0x00004000 ) mc68k_flags=(mc68k_flags|0x0002); }
|
|
if (data_size==32) { if( (0xC0000000&data)==0x80000000 || (0xC0000000&data)==0x40000000 ) mc68k_flags=(mc68k_flags|0x0002); }
|
|
|
|
data = data << 1; // Shift data to the left by one bit
|
|
shift_count--; // Decrement the shift_counter
|
|
}
|
|
|
|
if (dst_is_register==1) { Store_Data_Register(reg_num , data , data_size); } // Write-back the results to the register
|
|
else { Writeback_EA(calculated_EA , ea_type , data); } // Write-back the results to the EA
|
|
|
|
Calculate_Flag_Z(data , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
Calculate_Flag_N(data); // Calculate the N Flag
|
|
if (op_type==2) { mc68k_flags=(mc68k_flags&0xFFFD); } // Always clear the V flag for LSL
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_ROL(unsigned char dst_is_register)
|
|
{
|
|
unsigned long data;
|
|
unsigned char shift_count;
|
|
|
|
if (dst_is_register==1) { if (data_size==32) {clock_counter=clock_counter+4;} else {clock_counter=clock_counter+2;}
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
immediate = (0x0E00&first_opcode)>>9; // Isolate the Immediate number from the opcode
|
|
reg_num = (0x0007&first_opcode); // Isolate the register number from the opcode
|
|
data = Fetch_Data_Register(reg_num,data_size); // Fetch the register we want to shift
|
|
if ((0x0020&first_opcode) == 0) // T=0 for Immediate field contains the shift_count T=1 for shift_count contained in a register - Modulo-64
|
|
{ if(immediate==0) shift_count=8; else shift_count = immediate;
|
|
}
|
|
else
|
|
{ shift_count = (0x3F&Fetch_Data_Register(immediate,8));
|
|
}
|
|
}
|
|
else { clock_counter=clock_counter-2;
|
|
data_size = 16;
|
|
calculated_EA = Calculate_EA(0x0FE0); // Calculate the EA, checking supported modes
|
|
data = (Fetch_EA(calculated_EA , ea_type)); // Fetch the word data we want to shift from the EA
|
|
shift_count = 1;
|
|
}
|
|
|
|
|
|
while (shift_count!=0)
|
|
{
|
|
clock_counter=clock_counter+2;
|
|
if (data_size==8) { if( (0x00000080&data)==0) mc68k_flags=(mc68k_flags&0xFFFE); else mc68k_flags=(mc68k_flags|0x0001); } // Copy data[MSB] to the C flag
|
|
if (data_size==16) { if( (0x00008000&data)==0) mc68k_flags=(mc68k_flags&0xFFFE); else mc68k_flags=(mc68k_flags|0x0001); }
|
|
if (data_size==32) { if( (0x80000000&data)==0) mc68k_flags=(mc68k_flags&0xFFFE); else mc68k_flags=(mc68k_flags|0x0001); }
|
|
|
|
data = data << 1; // Shift data to the left by one bit
|
|
data = ( (mc68k_flags&0x0001) | data ); // Or the Carry Flag into bit[0] of the new data
|
|
shift_count--; // Decrement the shift_counter
|
|
}
|
|
|
|
if (dst_is_register==1) { Store_Data_Register(reg_num , data , data_size); } // Write-back the results to the register
|
|
else { Writeback_EA(calculated_EA , ea_type , data); } // Write-back the results to the EA
|
|
mc68k_flags=(mc68k_flags&0xFFFD); // Always clear the V flag
|
|
Calculate_Flag_Z(data , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
Calculate_Flag_N(data); // Calculate the N Flag
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_ROXL(unsigned char dst_is_register)
|
|
{
|
|
unsigned long data;
|
|
unsigned int old_X_Flag;
|
|
unsigned char shift_count;
|
|
|
|
if (dst_is_register==1) { if (data_size==32) {clock_counter=clock_counter+4;} else {clock_counter=clock_counter+2;}
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
immediate = (0x0E00&first_opcode)>>9; // Isolate the Immediate number from the opcode
|
|
reg_num = (0x0007&first_opcode); // Isolate the register number from the opcode
|
|
data = Fetch_Data_Register(reg_num,data_size); // Fetch the register we want to shift
|
|
if ((0x0020&first_opcode) == 0) // T=0 for Immediate field contains the shift_count T=1 for shift_count contained in a register - Modulo-64
|
|
{ if(immediate==0) shift_count=8; else shift_count = immediate;
|
|
}
|
|
else
|
|
{ shift_count = (0x3F&Fetch_Data_Register(immediate,8));
|
|
}
|
|
}
|
|
else { clock_counter=clock_counter-2;
|
|
data_size = 16;
|
|
calculated_EA = Calculate_EA(0x0FE0); // Calculate the EA, checking supported modes
|
|
data = (Fetch_EA(calculated_EA , ea_type)); // Fetch the word data we want to shift from the EA
|
|
shift_count = 1;
|
|
}
|
|
|
|
|
|
while (shift_count!=0)
|
|
{
|
|
clock_counter=clock_counter+2;
|
|
old_X_Flag = mc68k_flag_X;
|
|
if (data_size==8) { if( (0x00000080&data)==0) mc68k_flags=(mc68k_flags&0xFFEE); else mc68k_flags=(mc68k_flags|0x0011); } // Copy data[MSB] to the X and C flags
|
|
if (data_size==16) { if( (0x00008000&data)==0) mc68k_flags=(mc68k_flags&0xFFEE); else mc68k_flags=(mc68k_flags|0x0011); }
|
|
if (data_size==32) { if( (0x80000000&data)==0) mc68k_flags=(mc68k_flags&0xFFEE); else mc68k_flags=(mc68k_flags|0x0011); }
|
|
|
|
data = data << 1; // Shift data to the left by one bit
|
|
data = (old_X_Flag | data); // Or the original X Flag into bit[0] of the new data
|
|
shift_count--; // Decrement the shift_counter
|
|
}
|
|
|
|
if (dst_is_register==1) { Store_Data_Register(reg_num , data , data_size); } // Write-back the results to the register
|
|
else { Writeback_EA(calculated_EA , ea_type , data); } // Write-back the results to the EA
|
|
mc68k_flags=(mc68k_flags&0xFFFD); // Always clear the V flag
|
|
Calculate_Flag_Z(data , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
Calculate_Flag_N(data); // Calculate the N Flag
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
// op_type 1=ASR 2=LSR
|
|
// ----------------------------------------------------------------------
|
|
void op_xSR(unsigned char op_type , unsigned char dst_is_register)
|
|
{
|
|
unsigned long data;
|
|
unsigned char shift_count;
|
|
|
|
mc68k_flags=(mc68k_flags&0xFFFD); // Pre-clear the V flag
|
|
|
|
if (dst_is_register==1) { if (data_size==32) {clock_counter=clock_counter+4;} else {clock_counter=clock_counter+2;}
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
immediate = (0x0E00&first_opcode)>>9; // Isolate the Immediate number from the opcode
|
|
reg_num = (0x0007&first_opcode); // Isolate the register number from the opcode
|
|
data = Fetch_Data_Register(reg_num,data_size); // Fetch the register we want to shift
|
|
if ((0x0020&first_opcode) == 0) // T=0 for Immediate field contains the shift_count T=1 for shift_count contained in a register - Modulo-64
|
|
{ if(immediate==0) shift_count=8; else shift_count = immediate;
|
|
}
|
|
else
|
|
{ shift_count = (0x3F&Fetch_Data_Register(immediate,8));
|
|
}
|
|
}
|
|
else { clock_counter=clock_counter-2;
|
|
data_size = 16;
|
|
calculated_EA = Calculate_EA(0x0FE0); // Calculate the EA, checking supported modes
|
|
data = (Fetch_EA(calculated_EA , ea_type)); // Fetch the word data we want to shift from the EA
|
|
shift_count = 1;
|
|
}
|
|
|
|
|
|
while (shift_count!=0)
|
|
{
|
|
clock_counter=clock_counter+2;
|
|
if( (0x1&data)==0) mc68k_flags=(mc68k_flags&0xFFEE); else mc68k_flags=(mc68k_flags|0x0011); // Copy current data[0] to the X and C flags
|
|
|
|
if (data_size==8) { data = (0x000000FF&data)>>1; if (op_type==1 && (0x00000040&data)!=0) data=(0x00000080|data); } // Shift right.
|
|
if (data_size==16) { data = (0x0000FFFF&data)>>1; if (op_type==1 && (0x00004000&data)!=0) data=(0x00008000|data); } // For ASR: Copy old MSBit to new MSbit
|
|
if (data_size==32) { data = data >> 1; if (op_type==1 && (0x40000000&data)!=0) data=(0x80000000|data); }
|
|
|
|
shift_count--; // Decrement the shift_counter
|
|
}
|
|
|
|
if (dst_is_register==1) { Store_Data_Register(reg_num , data , data_size); } // Write-back the results to the register
|
|
else { Writeback_EA(calculated_EA , ea_type , data); } // Write-back the results to the EA
|
|
Calculate_Flag_Z(data , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
Calculate_Flag_N(data); // Calculate the N Flag
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_ROR(unsigned char dst_is_register)
|
|
{
|
|
unsigned long data;
|
|
unsigned char shift_count;
|
|
|
|
if (dst_is_register==1) { if (data_size==32) {clock_counter=clock_counter+4;} else {clock_counter=clock_counter+2;}
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
immediate = (0x0E00&first_opcode)>>9; // Isolate the Immediate number from the opcode
|
|
reg_num = (0x0007&first_opcode); // Isolate the register number from the opcode
|
|
data = Fetch_Data_Register(reg_num,data_size); // Fetch the register we want to shift
|
|
if ((0x0020&first_opcode) == 0) // T=0 for Immediate field contains the shift_count T=1 for shift_count contained in a register - Modulo-64
|
|
{ if(immediate==0) shift_count=8; else shift_count = immediate;
|
|
}
|
|
else
|
|
{ shift_count = (0x3F&Fetch_Data_Register(immediate,8));
|
|
}
|
|
}
|
|
else { clock_counter=clock_counter-2;
|
|
data_size = 16;
|
|
calculated_EA = Calculate_EA(0x0FE0); // Calculate the EA, checking supported modes
|
|
data = (Fetch_EA(calculated_EA , ea_type)); // Fetch the word data we want to shift from the EA
|
|
shift_count = 1;
|
|
}
|
|
|
|
|
|
while (shift_count!=0)
|
|
{
|
|
clock_counter=clock_counter+2;
|
|
if( (0x1&data)==0) mc68k_flags=(mc68k_flags&0xFFFE); else mc68k_flags=(mc68k_flags|0x0001); // Copy data[0] to the C flag
|
|
|
|
data = data >> 1;
|
|
if (data_size==8) { if (mc68k_flag_C==1) data=(0x00000080 | data); else data=(0xFFFFFF7F & data); } // Shift right. Copy data[0] to the MSbit
|
|
if (data_size==16) { if (mc68k_flag_C==1) data=(0x00008000 | data); else data=(0xFFFF7FFF & data); }
|
|
if (data_size==32) { if (mc68k_flag_C==1) data=(0x80000000 | data); else data=(0x7FFFFFFF & data); }
|
|
|
|
shift_count--; // Decrement the shift_counter
|
|
}
|
|
|
|
if (dst_is_register==1) { Store_Data_Register(reg_num , data , data_size); } // Write-back the results to the register
|
|
else { Writeback_EA(calculated_EA , ea_type , data); } // Write-back the results to the EA
|
|
mc68k_flags=(mc68k_flags&0xFFFD); // Always clear the V flag
|
|
Calculate_Flag_Z(data , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
Calculate_Flag_N(data); // Calculate the N Flag
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_ROXR(unsigned char dst_is_register)
|
|
{
|
|
unsigned long data;
|
|
unsigned int old_X_Flag;
|
|
unsigned char shift_count;
|
|
|
|
|
|
if (dst_is_register==1) { if (data_size==32) {clock_counter=clock_counter+4;} else {clock_counter=clock_counter+2;}
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
immediate = (0x0E00&first_opcode)>>9; // Isolate the Immediate number from the opcode
|
|
reg_num = (0x0007&first_opcode); // Isolate the register number from the opcode
|
|
data = Fetch_Data_Register(reg_num,data_size); // Fetch the register we want to shift
|
|
if ((0x0020&first_opcode) == 0) // T=0 for Immediate field contains the shift_count T=1 for shift_count contained in a register - Modulo-64
|
|
{ if(immediate==0) shift_count=8; else shift_count = immediate;
|
|
}
|
|
else
|
|
{ shift_count = (0x3F&Fetch_Data_Register(immediate,8));
|
|
}
|
|
}
|
|
else { clock_counter=clock_counter-2;
|
|
data_size = 16;
|
|
calculated_EA = Calculate_EA(0x0FE0); // Calculate the EA, checking supported modes
|
|
data = (Fetch_EA(calculated_EA , ea_type)); // Fetch the word data we want to shift from the EA
|
|
shift_count = 1;
|
|
}
|
|
|
|
while (shift_count!=0)
|
|
{
|
|
clock_counter=clock_counter+2;
|
|
old_X_Flag = mc68k_flag_X;
|
|
if( (0x1&data)==0) mc68k_flags=(mc68k_flags&0xFFEE); else mc68k_flags=(mc68k_flags|0x0011); // Copy data[0] to the C and X flags
|
|
|
|
data = data >> 1;
|
|
if (data_size==8) { if (old_X_Flag==1) data=(0x00000080 | data); else data=(0xFFFFFF7F & data); } else // Shift right. Copy X flag to the MSbit
|
|
if (data_size==16) { if (old_X_Flag==1) data=(0x00008000 | data); else data=(0xFFFF7FFF & data); } else
|
|
if (data_size==32) { if (old_X_Flag==1) data=(0x80000000 | data); else data=(0x7FFFFFFF & data); }
|
|
|
|
shift_count--; // Decrement the shift_counter
|
|
}
|
|
|
|
if (dst_is_register==1) { Store_Data_Register(reg_num , data , data_size); } // Write-back the results to the register
|
|
else { Writeback_EA(calculated_EA , ea_type , data); } // Write-back the results to the EA
|
|
mc68k_flags=(mc68k_flags&0xFFFD); // Always clear the V flag
|
|
Calculate_Flag_Z(data , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
Calculate_Flag_N(data); // Calculate the N Flag
|
|
return;
|
|
}
|
|
|
|
|
|
// bool_type: 1=OR 2=AND 3=EOR 4=CMP
|
|
// ----------------------------------------------------------------------
|
|
void op_BOOL(unsigned char bool_type)
|
|
{
|
|
unsigned long Reg_Data;
|
|
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
reg_num = (0x0E00&first_opcode)>>9;
|
|
Reg_Data = Fetch_Data_Register(reg_num,data_size);
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Pre-clear V, C Flags -- Will be calculated for CMP opcode
|
|
|
|
|
|
if ( (0x0100&first_opcode)==0) // EA is the source
|
|
{
|
|
if (bool_type==1) { calculated_EA=Calculate_EA(0x2FFC); EA_Data=Fetch_EA(calculated_EA,ea_type); result=EA_Data | Reg_Data; Store_Data_Register(reg_num,result,data_size); } else
|
|
if (bool_type==2) { calculated_EA=Calculate_EA(0x2FFC); EA_Data=Fetch_EA(calculated_EA,ea_type); result=EA_Data & Reg_Data; Store_Data_Register(reg_num,result,data_size); } else
|
|
if (bool_type==4) { calculated_EA=Calculate_EA(0x3FFC); EA_Data=Fetch_EA(calculated_EA,ea_type); result=Reg_Data - EA_Data; Calculate_Flags_C(Reg_Data , EA_Data , 1); Calculate_Flags_V(Reg_Data , EA_Data , result , data_size , 1); }
|
|
}
|
|
|
|
else // Register is the source
|
|
{
|
|
if (bool_type==1) { calculated_EA=Calculate_EA(0x0FE0); EA_Data=Fetch_EA(calculated_EA,ea_type); result = EA_Data | Reg_Data; Writeback_EA(calculated_EA , ea_type , result); } else
|
|
if (bool_type==2) { calculated_EA=Calculate_EA(0x0FE0); EA_Data=Fetch_EA(calculated_EA,ea_type); result = EA_Data & Reg_Data; Writeback_EA(calculated_EA , ea_type , result); } else
|
|
if (bool_type==3) { calculated_EA=Calculate_EA(0x2FE0); EA_Data=Fetch_EA(calculated_EA,ea_type); result = EA_Data ^ Reg_Data; Writeback_EA(calculated_EA , ea_type , result); }
|
|
}
|
|
|
|
Calculate_Flag_N(result); // Calculate the N Flag
|
|
Calculate_Flag_Z(result , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// bool_type: 1=ORI 2=ANDI 3=EORI 4=CMPI
|
|
// ----------------------------------------------------------------------
|
|
void op_BOOL_I(unsigned char bool_type)
|
|
{
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
immediate = Fetch_Immediate(data_size); // Fetch the immediate operand of the correct data size
|
|
|
|
if (data_size==32) clock_counter=clock_counter+3;
|
|
|
|
calculated_EA = Calculate_EA(0x2FE3); // Calculate the EA, checking supported modes
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Pre-clear V, C Flags
|
|
|
|
EA_Data = Fetch_EA(calculated_EA , ea_type); // Fetch the EA operand
|
|
|
|
// Perform the operation then write-back the result to the EA
|
|
if (bool_type==1) { result = EA_Data | immediate; Writeback_EA(calculated_EA , ea_type , result); } else
|
|
if (bool_type==2) { result = EA_Data & immediate; Writeback_EA(calculated_EA , ea_type , result); } else
|
|
if (bool_type==3) { result = EA_Data ^ immediate; Writeback_EA(calculated_EA , ea_type , result); } else
|
|
if (bool_type==4) { result = EA_Data - immediate; Calculate_Flags_C(EA_Data , immediate , 1); Calculate_Flags_V(EA_Data , immediate , result , data_size , 1); } // Calculate the V and C Flags for CMPI
|
|
Calculate_Flag_N(result); // Calculate the N Flag
|
|
Calculate_Flag_Z(result , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_CMPA()
|
|
{
|
|
unsigned long Reg_Data;
|
|
|
|
clock_counter=clock_counter+2;
|
|
|
|
data_size = DATA_SIZE_TYPE_D; // Get the data size from the opcode bits8]
|
|
calculated_EA=Calculate_EA(0x3FFC); // Calculate the EA, checking supported modes
|
|
EA_Data=Fetch_EA(calculated_EA,ea_type); // Fetch the EA data
|
|
|
|
reg_num = (0x0E00&first_opcode)>>9; // Isolate the register number from the opcode
|
|
Reg_Data = Fetch_Address_Register(reg_num,32); // Fetch the Address Register data
|
|
|
|
if (data_size==16) { EA_Data=Sign_Extend(EA_Data,16); } // Sign extend source operand for word
|
|
|
|
result = Reg_Data - EA_Data ;
|
|
|
|
data_size = 32; // Force the size to 32-bit for flag calculations
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Pre-clear V, C Flags
|
|
Calculate_Flags_C(Reg_Data , EA_Data , 1);
|
|
Calculate_Flags_V(Reg_Data , EA_Data , result , data_size , 1); // Calculate the V and C Flags
|
|
Calculate_Flag_N(result); // Calculate the N Flag
|
|
Calculate_Flag_Z(result , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_CMPM()
|
|
{
|
|
unsigned char regX;
|
|
unsigned char regY;
|
|
unsigned long AddrX;
|
|
unsigned long AddrY;
|
|
unsigned long DataX;
|
|
unsigned long DataY;
|
|
|
|
clock_counter=clock_counter+2;
|
|
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
|
|
regX = (0x0E00&first_opcode)>>9; // Isolate the register X number from the opcode
|
|
regY = (0x0007&first_opcode); // Isolate the register Y number from the opcode
|
|
|
|
|
|
AddrX = Fetch_Address_Register(regX,32); // Fetch Address Register X data
|
|
AddrY = Fetch_Address_Register(regY,32); // Fetch Address Register Y data
|
|
|
|
if (data_size==8) { Store_Address_Register(regX,AddrX+0x1,32); Store_Address_Register(regY,AddrY+0x1,32); } // Post-increment both addresses (An)+
|
|
if (data_size==16) { Store_Address_Register(regX,AddrX+0x2,32); Store_Address_Register(regY,AddrY+0x2,32); }
|
|
if (data_size==32) { Store_Address_Register(regX,AddrX+0x4,32); Store_Address_Register(regY,AddrY+0x4,32); }
|
|
|
|
|
|
if (data_size==32) { DataX=BIU_Read_32(AddrX); DataY=BIU_Read_32(AddrY); } // Fetch data from both addresses
|
|
else { DataX=BIU_Read(AddrX,data_size); DataY=BIU_Read(AddrY,data_size); }
|
|
|
|
result = DataX - DataY ;
|
|
|
|
Calculate_Flag_N(result); // Calculate the N Flag
|
|
Calculate_Flag_Z(result , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Pre-clear V, C Flags
|
|
Calculate_Flags_C(DataX , DataY , 1);
|
|
Calculate_Flags_V(DataX , DataY , result , data_size , 1); // Calculate the V and C Flags
|
|
return;
|
|
}
|
|
|
|
|
|
// math_type 0=SUB 1=ADD
|
|
// ----------------------------------------------------------------------
|
|
void op_ADDSUB(unsigned char math_type)
|
|
{
|
|
signed long long Reg_Data;
|
|
|
|
if ( (0x0100&first_opcode)==0) // ** EA is the source **
|
|
{
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
calculated_EA = Calculate_EA(0x3FFF); // Calculate the EA, checking supported modes
|
|
EA_Data = Fetch_EA(calculated_EA , ea_type); // Fetch the EA data
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Pre-clear V, C Flags
|
|
|
|
reg_num = (0x0E00&first_opcode)>>9; // Isolate the register number from the opcode
|
|
Reg_Data = Fetch_Data_Register(reg_num,data_size); // Fetch the Register data
|
|
|
|
if (math_type==0) { result = Reg_Data - EA_Data; Calculate_Flags_C(Reg_Data , EA_Data , 1); Calculate_Flags_V(Reg_Data , EA_Data , result , data_size , 1); } // Calculate the results and the C,V Flags
|
|
if (math_type==1) { result = Reg_Data + EA_Data; Calculate_Flags_C(Reg_Data , EA_Data , 0); Calculate_Flags_V(Reg_Data , EA_Data , result , data_size , 0); }
|
|
|
|
Store_Data_Register(reg_num,result,data_size); // Write-back the results to the Data Register
|
|
}
|
|
|
|
else // ** Register is the source **
|
|
{
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
calculated_EA = Calculate_EA(0x0FE0); // Calculate the EA, checking supported modes
|
|
EA_Data = Fetch_EA(calculated_EA , ea_type); // Fetch the EA data
|
|
|
|
reg_num = (0x0E00&first_opcode)>>9; // Isolate the register number from the opcode
|
|
Reg_Data = Fetch_Data_Register(reg_num,data_size); // Fetch the Register data
|
|
|
|
if (math_type==0) { result = EA_Data - Reg_Data; Calculate_Flags_C(EA_Data , Reg_Data , 1); Calculate_Flags_V(EA_Data , Reg_Data , result , data_size , 1); } // Calculate the results and the C,V Flags
|
|
if (math_type==1) { result = EA_Data + Reg_Data; Calculate_Flags_C(EA_Data , Reg_Data , 0); Calculate_Flags_V(EA_Data , Reg_Data , result , data_size , 0); }
|
|
|
|
Writeback_EA(calculated_EA , ea_type , result); // Write-back the results to the EA
|
|
}
|
|
|
|
Calculate_Flag_N(result); // Calculate the N Flag
|
|
Calculate_Flag_Z(result , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
if (mc68k_flag_C != 0) { mc68k_flags=(mc68k_flags | 0x0010); } // Copy C flag to X flag
|
|
else { mc68k_flags=(mc68k_flags & 0xFFEF); }
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// math_type 0=SUB 1=ADD
|
|
// ----------------------------------------------------------------------
|
|
void op_ADDSUBA(unsigned char math_type)
|
|
{
|
|
unsigned long Reg_Data;
|
|
unsigned long result=0;
|
|
|
|
|
|
data_size = DATA_SIZE_TYPE_D; // Get the data size from the opcode bit[8]
|
|
calculated_EA = Calculate_EA(0x3FFC); // Calculate the EA, checking supported modes
|
|
EA_Data = Fetch_EA(calculated_EA , ea_type); // Fetch the EA data
|
|
|
|
reg_num = (0x0E00&first_opcode)>>9; // Isolate the register number from the opcode
|
|
Reg_Data = Fetch_Address_Register(reg_num,data_size); // Fetch the Register data
|
|
|
|
if (math_type==0) result = Reg_Data - EA_Data; // Calculate the results
|
|
if (math_type==1) result = Reg_Data + EA_Data;
|
|
|
|
Store_Address_Register(reg_num,result,32); // Write-back the results to the 32-bits of the Address Register
|
|
return;
|
|
}
|
|
|
|
|
|
// math_type 0=SUB 1=ADD
|
|
// ----------------------------------------------------------------------
|
|
void op_ADDSUBI(unsigned char math_type)
|
|
{
|
|
unsigned long result=0;
|
|
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
immediate = Fetch_Immediate(data_size); // Fetch the immediate operand of the correct data size
|
|
|
|
if (data_size==32) clock_counter=clock_counter+4;
|
|
|
|
calculated_EA = Calculate_EA(0x2FE0); // Calculate the EA, checking supported modes
|
|
EA_Data = Fetch_EA(calculated_EA , ea_type); // Fetch the EA data
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Pre-clear V, C Flags
|
|
|
|
|
|
if (math_type==0) { result = EA_Data - immediate; Calculate_Flags_C(EA_Data , immediate , 1); Calculate_Flags_V(EA_Data , immediate , result , data_size , 1); } // Calculate the results and the C,V Flags
|
|
if (math_type==1) { result = EA_Data + immediate; Calculate_Flags_C(EA_Data , immediate , 0); Calculate_Flags_V(EA_Data , immediate , result , data_size , 0); }
|
|
|
|
Writeback_EA(calculated_EA , ea_type , result); // Write-back the results to the EA
|
|
|
|
Calculate_Flag_N(result); // Calculate the N Flag
|
|
Calculate_Flag_Z(result , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
if (mc68k_flag_C != 0) { mc68k_flags=(mc68k_flags | 0x0010); } // Copy C flag to X flag
|
|
else { mc68k_flags=(mc68k_flags & 0xFFEF); }
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// math_type 0=SUB 1=ADD
|
|
// ----------------------------------------------------------------------
|
|
void op_ADDSUBQ(unsigned char math_type)
|
|
{
|
|
unsigned long long result=0;
|
|
unsigned long opcode_data;
|
|
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
calculated_EA = Calculate_EA(0x3FE0); // Calculate the EA, checking supported modes
|
|
EA_Data = Fetch_EA(calculated_EA , ea_type); // Fetch the EA data
|
|
|
|
opcode_data = (0x0E00&first_opcode)>>9; // Isolate the immediate "Q" data from the opcode
|
|
if (opcode_data==0) opcode_data=8;
|
|
|
|
if (math_type==0) { result = EA_Data - opcode_data; } // Calculate the results
|
|
if (math_type==1) { result = EA_Data + opcode_data; }
|
|
|
|
Writeback_EA(calculated_EA , ea_type , result); // Write-back the results to the EA
|
|
|
|
if (ea_type != ADDRESS_REG) // Don't set flags if destination is an Address register
|
|
{
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Pre-clear V, C Flags
|
|
if (math_type==0) { Calculate_Flags_C(EA_Data , opcode_data , 1); Calculate_Flags_V(EA_Data , opcode_data , result , data_size , 1 ); }
|
|
if (math_type==1) { Calculate_Flags_C(EA_Data , opcode_data , 0); Calculate_Flags_V(EA_Data , opcode_data , result , data_size , 0 ); }
|
|
Calculate_Flag_N(result); // Calculate the N Flag
|
|
Calculate_Flag_Z(result , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
if (mc68k_flag_C != 0) { mc68k_flags=(mc68k_flags | 0x0010); } // Copy C flag to X flag
|
|
else { mc68k_flags=(mc68k_flags & 0xFFEF); }
|
|
}
|
|
else
|
|
{
|
|
clock_counter=clock_counter+4;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// math_type 0=SUBX 1=ADDX
|
|
// ----------------------------------------------------------------------
|
|
void op_ADDSUBX(unsigned char math_type)
|
|
{
|
|
unsigned char regX;
|
|
unsigned char regY;
|
|
unsigned long AddrX;
|
|
unsigned long AddrY;
|
|
unsigned long DataX;
|
|
unsigned long DataY;
|
|
unsigned long long result=0;
|
|
|
|
data_size = DATA_SIZE_TYPE_A; // Get the data size from the opcode bits[7:6]
|
|
|
|
regX = (0x0E00&first_opcode)>>9; // Isolate the register X number from the opcode
|
|
regY = (0x0007&first_opcode); // Isolate the register Y number from the opcode
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Pre-clear V, C Flags
|
|
|
|
|
|
if ( (0x0008&first_opcode)==0) // ** Register to Register **
|
|
{
|
|
DataX = Fetch_Data_Register(regX,data_size); // Fetch Data Register X data
|
|
DataY = Fetch_Data_Register(regY,data_size); // Fetch Data Register Y data
|
|
|
|
|
|
if (math_type==0) { Calculate_Flags_C(DataX , DataY , 1);
|
|
result = DataX - DataY; // Subtract the two operands first and calculate the V,C Flags
|
|
Calculate_Flags_C(result , mc68k_flag_X , 1);
|
|
result = result - mc68k_flag_X;
|
|
Calculate_Flags_V(DataX , DataY , result , data_size , 1);
|
|
}
|
|
|
|
if (math_type==1) { Calculate_Flags_C(DataX , DataY , 0);
|
|
result = DataX + DataY; // Add the two operands first and calculate the V,C Flags
|
|
Calculate_Flags_C(result , mc68k_flag_X , 0);
|
|
result = result + mc68k_flag_X;
|
|
Calculate_Flags_V(DataX , DataY , result , data_size , 0);
|
|
}
|
|
|
|
Store_Data_Register(regX,result,data_size); // Write-back the results to the Data Register
|
|
}
|
|
|
|
else // ** Memory to Memory **
|
|
{
|
|
|
|
clock_counter=clock_counter+2;
|
|
AddrX = Fetch_Address_Register(regX,32); // Fetch Address Register X data
|
|
AddrY = Fetch_Address_Register(regY,32); // Fetch Address Register Y data
|
|
|
|
if (data_size==8) { AddrX = AddrX - 0x1; AddrY = AddrY - 0x1; } // Pre-decrement both addresses -(An)
|
|
if (data_size==16) { AddrX = AddrX - 0x2; AddrY = AddrY - 0x2; }
|
|
if (data_size==32) { AddrX = AddrX - 0x4; AddrY = AddrY - 0x4; }
|
|
|
|
Store_Address_Register(regX,AddrX,32); // Write-back the -(An) address both Address Registers
|
|
Store_Address_Register(regY,AddrY,32);
|
|
|
|
|
|
if (data_size==32) { DataX=BIU_Read_32(AddrX); DataY=BIU_Read_32(AddrY); } // Fetch data from both addresses
|
|
else { DataX=BIU_Read(AddrX,data_size); DataY=BIU_Read(AddrY,data_size); }
|
|
|
|
if (math_type==0) { Calculate_Flags_C(DataX , DataY , 1);
|
|
result = DataX - DataY; // Subtract the two operands first and calculate the V,C Flags
|
|
Calculate_Flags_C(result , mc68k_flag_X , 1);
|
|
result = result - mc68k_flag_X;
|
|
Calculate_Flags_V(DataX , DataY , result , data_size , 1);
|
|
}
|
|
|
|
if (math_type==1) { Calculate_Flags_C(DataX , DataY , 0);
|
|
result = DataX + DataY; // Add the two operands first and calculate the V,C Flags
|
|
Calculate_Flags_C(result , mc68k_flag_X , 0);
|
|
result = result + mc68k_flag_X;
|
|
Calculate_Flags_V(DataX , DataY , result , data_size , 0);
|
|
}
|
|
|
|
if (data_size==8) { BIU_Write(AddrX , result , 8); }
|
|
if (data_size==16) { BIU_Write(AddrX , result , 16); }
|
|
if (data_size==32) { clock_counter=clock_counter+4; BIU_Write_32(AddrX , result ); }
|
|
|
|
|
|
}
|
|
Calculate_Flag_N(result); // Calculate the N Flag
|
|
Calculate_Flag_Z(result , TRUE); // Calculate the Z Flag - Clear_only = TRUE
|
|
if (mc68k_flag_C != 0) { mc68k_flags=(mc68k_flags | 0x0010); } // Copy C flag to X flag
|
|
else { mc68k_flags=(mc68k_flags & 0xFFEF); }
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_DIVS()
|
|
{
|
|
signed long long dividend;
|
|
signed long long divisor;
|
|
signed long long quotient;
|
|
signed long long remainder;
|
|
unsigned long long result;
|
|
|
|
clock_counter=clock_counter+154;
|
|
|
|
data_size = 16; // Get the data size from the opcode bits[7:6]
|
|
calculated_EA = Calculate_EA(0x2FFC); // Calculate the EA, checking supported modes
|
|
divisor = (signed short int) (Fetch_EA(calculated_EA , ea_type) ); // Fetch the EA data and convert to a signed 16-bit number
|
|
|
|
reg_num = (0x0E00&first_opcode)>>9; // Isolate the register number from the opcode
|
|
dividend = (signed long) Fetch_Data_Register(reg_num,32); // Fetch the Register data and convert to a signed 32-bit number
|
|
|
|
if (divisor==0) { clock_counter=6; Exception_Handler(5); return; } // Check for division by zero. Trap if true
|
|
else
|
|
{
|
|
quotient = dividend / divisor; // Calculate the results
|
|
remainder = (0xFFFF & (dividend % divisor ) );
|
|
result = ( (remainder<<16) | (0x0000FFFF"ient) );
|
|
|
|
|
|
if ( (quotient > 32767) || (quotient < -32768) ) { mc68k_flags = (mc68k_flags | 0x0002); // If overflow, set the V Flag and don't update the register
|
|
mc68k_flags=(mc68k_flags&0xFFFE); // Always clear the C Flag
|
|
}
|
|
|
|
else { Store_Data_Register(reg_num,result,32); // Else, write-back the 32-bit results to the Data Register
|
|
mc68k_flags=(mc68k_flags&0xFFFC); // Clear the V and C flag
|
|
Calculate_Flag_N((0x0000FFFF"ient));
|
|
Calculate_Flag_Z((0x0000FFFF"ient) , FALSE);
|
|
}
|
|
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_DIVU()
|
|
{
|
|
unsigned long dividend;
|
|
unsigned long divisor;
|
|
unsigned long quotient;
|
|
unsigned long remainder;
|
|
unsigned long result;
|
|
|
|
clock_counter=clock_counter+136;
|
|
|
|
data_size = 16; // Get the data size from the opcode bits[7:6]
|
|
calculated_EA = Calculate_EA(0x2FFC); // Calculate the EA, checking supported modes
|
|
divisor = Fetch_EA(calculated_EA , ea_type); // Fetch the EA data
|
|
|
|
reg_num = (0x0E00&first_opcode)>>9; // Isolate the register number from the opcode
|
|
dividend = Fetch_Data_Register(reg_num,32); // Fetch the Register data
|
|
|
|
if (divisor==0) { Exception_Handler(5); return; } // Check for division by zero. Trap if true
|
|
else
|
|
{
|
|
quotient = dividend / divisor; // Calculate the results
|
|
remainder = (0xFFFF & (dividend % divisor ) );
|
|
result = ( (remainder<<16) | (0x0000FFFF"ient) );
|
|
|
|
if ( (quotient>0xFFFF) ) { mc68k_flags = (mc68k_flags | 0x0002); // If overflow, set the V Flag and don't update the register
|
|
mc68k_flags=(mc68k_flags&0xFFFE); // Always clear the C Flag
|
|
}
|
|
|
|
else { Store_Data_Register(reg_num,result,32); // Else, write-back the 32-bit results to the Data Register
|
|
mc68k_flags=(mc68k_flags&0xFFFC); // Clear the V and C flag
|
|
Calculate_Flag_N((0x0000FFFF"ient));
|
|
Calculate_Flag_Z((0x0000FFFF"ient) , FALSE);
|
|
}
|
|
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_MULS()
|
|
{
|
|
signed short int reg_data_s;
|
|
signed short int ea_data_s;
|
|
signed long result;
|
|
unsigned long wb_result;
|
|
|
|
clock_counter=clock_counter+66;
|
|
|
|
data_size = 16; // Force size to 16
|
|
calculated_EA = Calculate_EA(0x2FFC); // Calculate the EA, checking supported modes
|
|
ea_data_s = (signed short int) Fetch_EA(calculated_EA , ea_type); // Fetch the EA data and convert to a signed 16-bit number
|
|
|
|
reg_num = (0x0E00&first_opcode)>>9; // Isolate the register number from the opcode
|
|
reg_data_s = (signed short int) Fetch_Data_Register(reg_num,16); // Fetch the Register data and convert to a signed 16-bit number
|
|
|
|
result = (signed long)ea_data_s * (signed long)reg_data_s; // Calculate the results
|
|
|
|
wb_result = (unsigned long ) result;
|
|
|
|
Store_Data_Register(reg_num,result,32); // Write-back the full 32-bits of the results to the Data Register
|
|
|
|
data_size = 32; // Force size to 32-bits so flags are calculated correctly
|
|
Calculate_Flag_N(wb_result); // Calculate the N Flag
|
|
Calculate_Flag_Z(wb_result , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Always clear V, C Flags
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_MULU()
|
|
{
|
|
unsigned long reg_data;
|
|
unsigned long result;
|
|
|
|
clock_counter=clock_counter+66;
|
|
|
|
data_size = 16; // Force size to 16
|
|
calculated_EA = Calculate_EA(0x2FFC); // Calculate the EA, checking supported modes
|
|
EA_Data = Fetch_EA(calculated_EA , ea_type); // Fetch the EA data
|
|
|
|
reg_num = (0x0E00&first_opcode)>>9; // Isolate the register number from the opcode
|
|
reg_data = Fetch_Data_Register(reg_num,16); // Fetch the Register data
|
|
|
|
result = (unsigned long)EA_Data * (unsigned long)reg_data; // Calculate the results
|
|
|
|
Store_Data_Register(reg_num,result,32); // Write-back the full 32-bits of the results to the Data Register
|
|
|
|
data_size = 32; // Force size to 32-bits so flags are calculated correctly
|
|
Calculate_Flag_N(result); // Calculate the N Flag
|
|
Calculate_Flag_Z(result , FALSE); // Calculate the Z Flag - Clear_only = FALSE
|
|
mc68k_flags = ( mc68k_flags & 0xFFFC); // Always clear V, C Flags
|
|
return;
|
|
}
|
|
|
|
|
|
// bcd_type 0=ABCD 1=SBCD
|
|
// ----------------------------------------------------------------------
|
|
void op_xBCD(unsigned char bcd_type)
|
|
{
|
|
unsigned char regX;
|
|
unsigned char regY;
|
|
unsigned long AddrX;
|
|
unsigned long AddrY;
|
|
signed long result;
|
|
signed long DataX;
|
|
signed long DataY;
|
|
int result_lower;
|
|
int result_upper;
|
|
signed char carry=0;
|
|
|
|
clock_counter=clock_counter+2;
|
|
data_size = 8; // Byte only
|
|
|
|
regX = (0x0E00&first_opcode)>>9; // Isolate the register X number from the opcode
|
|
regY = (0x0007&first_opcode); // Isolate the register Y number from the opcode
|
|
|
|
if ( (0x0008&first_opcode)==0) // ** Opcode[3]=0 for Register to Register **
|
|
{
|
|
DataX = Fetch_Data_Register(regX,data_size); // Fetch Data Register X data
|
|
DataY = Fetch_Data_Register(regY,data_size); // Fetch Data Register Y data
|
|
|
|
|
|
if (bcd_type==0) // ## ABCD##
|
|
{
|
|
carry = 0;
|
|
result_lower = (0x0F&DataX) + (0x0F&DataY) + mc68k_flag_X; // Lower BCD digit
|
|
if (result_lower>9) { result_lower = result_lower - 10; carry = 1; }
|
|
|
|
result_upper = ((0xF0&DataX)>>4) + ((0xF0&DataY)>>4) + carry; // Upper BCD digit
|
|
carry = 0;
|
|
if (result_upper>9) { result_upper = result_upper - 10; carry = 1; }
|
|
|
|
result = (result_upper<<4) + result_lower;
|
|
}
|
|
|
|
else // ## SBCD ##
|
|
{
|
|
carry = 0;
|
|
result_lower = (0x0F&DataX) - (0x0F&DataY) - mc68k_flag_X; // Lower BCD digit
|
|
if (result_lower<0) { result_lower = result_lower + 10; carry = 1; }
|
|
|
|
result_upper = ((0xF0&DataX)>>4) - ((0xF0&DataY)>>4) - carry; // Upper BCD digit
|
|
carry = 0;
|
|
if (result_upper<0) { result_upper = result_upper + 10; carry = 1; }
|
|
|
|
result = (result_upper<<4) + result_lower;
|
|
}
|
|
|
|
Store_Data_Register(regX,result,data_size); // Write-back the results to the Data Register
|
|
}
|
|
|
|
else // ** Memory to Memory **
|
|
{
|
|
AddrX = Fetch_Address_Register(regX,32); // Fetch Address Register X data
|
|
AddrY = Fetch_Address_Register(regY,32); // Fetch Address Register Y data
|
|
|
|
AddrX = AddrX - 0x1; // Pre-decrement both addresses -(An)
|
|
AddrY = AddrY - 0x1;
|
|
|
|
Store_Address_Register(regX,AddrX,32); // Write-back the -(An) address both Address Registers
|
|
Store_Address_Register(regY,AddrY,32);
|
|
|
|
DataX = BIU_Read(AddrX , data_size); // Fetch data from both addresses
|
|
DataY = BIU_Read(AddrY , data_size);
|
|
|
|
|
|
if (bcd_type==0) // ## ABCD##
|
|
{
|
|
carry = 0;
|
|
result_lower = (0x0F&DataX) + (0x0F&DataY) + mc68k_flag_X; // Lower BCD digit
|
|
if (result_lower>9) { result_lower = result_lower - 10; carry = 1; }
|
|
|
|
result_upper = ((0xF0&DataX)>>4) + ((0xF0&DataY)>>4) + carry; // Upper BCD digit
|
|
carry = 0;
|
|
if (result_upper>9) { result_upper = result_upper - 10; carry = 1; }
|
|
|
|
result = (result_upper<<4) + result_lower;
|
|
}
|
|
|
|
else // ## SBCD ##
|
|
{
|
|
carry = 0;
|
|
result_lower = (0x0F&DataX) - (0x0F&DataY) - mc68k_flag_X; // Lower BCD digit
|
|
if (result_lower<0) { result_lower = result_lower + 10; carry = 1; }
|
|
|
|
result_upper = ((0xF0&DataX)>>4) - ((0xF0&DataY)>>4) - carry; // Upper BCD digit
|
|
carry = 0;
|
|
if (result_upper<0) { result_upper = result_upper + 10; carry = 1; }
|
|
|
|
result = (result_upper<<4) + result_lower;
|
|
}
|
|
|
|
Writeback_EA(AddrX , MEMORY , result); // Write-back the results to Memory
|
|
}
|
|
|
|
if (carry==1) mc68k_flags=(mc68k_flags|0x0011); else mc68k_flags=(mc68k_flags&0xFFEE); // Set X and C Flags to the Carry bit
|
|
Calculate_Flag_Z(result , TRUE); // Calculate the Z Flag - Clear_only = TRUE
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_NBCD()
|
|
{
|
|
int result_lower;
|
|
int result_upper;
|
|
signed long result;
|
|
signed char carry=0;
|
|
|
|
data_size = 8;
|
|
calculated_EA = Calculate_EA(0x2FE0); // Calculate the Source EA, checking supported modes
|
|
EA_Data = Fetch_EA(calculated_EA , ea_type); // Fetch the EA data
|
|
|
|
|
|
result_lower = (0x0) - (0x0F&EA_Data) - mc68k_flag_X; // Lower BCD digit
|
|
if (result_lower<0) { result_lower = result_lower + 10; carry = 1; }
|
|
|
|
result_upper = (0x0) - ((0xF0&EA_Data)>>4) - carry; // Upper BCD digit
|
|
carry = 0;
|
|
if (result_upper<0) { result_upper = result_upper + 10; carry = 1; }
|
|
|
|
result = (result_upper<<4) + result_lower;
|
|
|
|
Writeback_EA(calculated_EA , ea_type ,result); // Write-back data to the EA
|
|
|
|
if (carry==1) mc68k_flags=(mc68k_flags|0x0011); else mc68k_flags=(mc68k_flags&0xFFEE); // Set X and C Flags to the Carry bit
|
|
Calculate_Flag_Z(result , TRUE); // Calculate the Z Flag - Clear_only = TRUE
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
void op_MOVEP()
|
|
{
|
|
unsigned char regX;
|
|
unsigned long DataX;
|
|
unsigned long result=0;
|
|
|
|
if ( (0x0040&first_opcode) == 0) data_size = 16; else data_size = 32; // Isolate opcode[6] to set the size
|
|
|
|
first_opcode = first_opcode | 0x20; // Force the EA field to d16(An) mode
|
|
calculated_EA = Calculate_EA(0x0100); // Calculate the EA with the forced EA mode
|
|
regX = (0x0E00&first_opcode)>>9; // Isolate the register X number from the opcode
|
|
|
|
|
|
if ( (0x0080&first_opcode) == 0) // ## Memory to Register ##
|
|
{
|
|
clock_counter=16;
|
|
result = (0xFF&BIU_Read(calculated_EA+0x0 , SIZE_BYTE)); result = result<<8; // Byte #0
|
|
result = result | (0xFF&BIU_Read(calculated_EA+0x2 , SIZE_BYTE)); // Byte #1
|
|
Store_Data_Register(regX,result,16); // Write-back the results to 16 bits of the Data Register
|
|
result = result<<8; // Keep shifting for possible word operation
|
|
if (data_size==32) { clock_counter=clock_counter+8;
|
|
result = result | (0xFF&BIU_Read(calculated_EA+0x4 , SIZE_BYTE)); result = result<<8; // Byte #2 for Long data
|
|
result = result | (0xFF&BIU_Read(calculated_EA+0x6 , SIZE_BYTE)); // Byte #3 for Long data
|
|
Store_Data_Register(regX,result,32); // Write-back the results to the full Data Register
|
|
}
|
|
}
|
|
|
|
else // ## Register to Memory ##
|
|
{
|
|
DataX = Fetch_Data_Register(regX,32); // Fetch Data Register X data
|
|
|
|
if (data_size==16) { clock_counter=16;
|
|
BIU_Write(calculated_EA+0x0 , ( (0x0000FF00&DataX)>>8) , SIZE_BYTE); // Byte #0
|
|
BIU_Write(calculated_EA+0x2 , ( (0x000000FF&DataX)>>0) , SIZE_BYTE); // Byte #1
|
|
}
|
|
|
|
else { clock_counter=clock_counter+8;
|
|
BIU_Write(calculated_EA+0x0 , ( (0xFF000000&DataX)>>24) , SIZE_BYTE); // Byte #0
|
|
BIU_Write(calculated_EA+0x2 , ( (0x00FF0000&DataX)>>16) , SIZE_BYTE); // Byte #1
|
|
BIU_Write(calculated_EA+0x4 , ( (0x0000FF00&DataX)>>8 ) , SIZE_BYTE); // Byte #2
|
|
BIU_Write(calculated_EA+0x6 , ( (0x000000FF&DataX)>>0 ) , SIZE_BYTE); // Byte #3
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
// Main MCL68 loop
|
|
// ----------------------------------------------------------------------
|
|
void loop() {
|
|
|
|
uint8_t inchar=0;
|
|
uint16_t joe16, joe17=0;
|
|
uint16_t failcnt=0;
|
|
//setup();
|
|
|
|
delay(2000); // Delay a few seconds to give the UART to establish a link with the host PC
|
|
for (uint32_t i=0 ; i<=3200 ; i++) { wait_for_E_falling_edge(); }
|
|
|
|
|
|
|
|
// Load the Macintosh 512K's ROM into internal 64KB ROM
|
|
rom_readthrough=1;
|
|
for (uint32_t i=0x0 ; i<=0x0FFFF ; i=i+1) { INTERNAL_ROM[i] = BIU_Read(i , SIZE_BYTE); }
|
|
rom_readthrough=0;
|
|
|
|
|
|
|
|
Reset_routine();
|
|
|
|
|
|
while (1)
|
|
{
|
|
|
|
// Wait for opcode cycle counter to expire before processing traps or next instruction
|
|
// Allow prefetch queue to fill during this time
|
|
while (clock_counter>0) {
|
|
wait_for_CLK_falling_edge(); //Serial.printf("%d\n\r",clock_counter);
|
|
clock_counter--;
|
|
if (prefetch_queue_count<2) BIU_PFQ_add_word();
|
|
}
|
|
|
|
|
|
// Extract these signals at the last clock edge
|
|
gpio6_data = GPIO6_DR;
|
|
gpio6_reset_n = gpio6_data & RESET_n_BIT;
|
|
gpio6_halt_n = gpio6_data & HALT_n_BIT;
|
|
gpio6_ipl = (0x7 ^ (gpio6_data & IPL2_0_BITs)>>16 ); // Invert the IPL bits which are active low on the pins
|
|
if (gpio6_ipl != 7) nmi_gate=0; // Debounce NMI
|
|
|
|
|
|
// Handle a RESET from the BIU
|
|
if ((gpio6_reset_n == 0) && (gpio6_halt_n == 0) ) Reset_routine();
|
|
|
|
//if (mc68k_flag_INTR_Mask != 7) Serial.printf("\n\r gpio6_ipl:%x: mc68k_flag_INTR_Mask:%x ",gpio6_ipl,mc68k_flag_INTR_Mask);
|
|
// Interrupts
|
|
if (nmi_gate==0 && gpio6_ipl==7) { nmi_gate=1; Exception_Handler(99); } // NMI - only allow once until IPL[2:0] changes to different value
|
|
else if (gpio6_ipl > mc68k_flag_INTR_Mask) { Exception_Handler(99); } // Maskable interrupt
|
|
|
|
|
|
else
|
|
|
|
{
|
|
first_opcode = BIU_PFQ_Fetch();
|
|
|
|
//Serial.printf("first_opcode %x\n\r",first_opcode);
|
|
//Serial.printf("\n\r %x: %x ",(mc68k_pc-2),first_opcode);
|
|
|
|
switch (first_opcode&0xF000)
|
|
{
|
|
case (0x0000):
|
|
if ((first_opcode&0x0FFF)==0x003C) { op_BOOL_I_TO_CCR(1); break; }
|
|
if ((first_opcode&0x0FFF)==0x007C) { op_BOOL_I_TO_SR(1); break; }
|
|
if ((first_opcode&0x0FFF)==0x0A3C) { op_BOOL_I_TO_CCR(3); break; }
|
|
if ((first_opcode&0x0FFF)==0x0A7C) { op_BOOL_I_TO_SR(3); break; }
|
|
if ((first_opcode&0x0FFF)==0x023C) { op_BOOL_I_TO_CCR(2); break; }
|
|
if ((first_opcode&0x0FFF)==0x027C) { op_BOOL_I_TO_SR(2); break; }
|
|
if ((first_opcode&0x0FC0)==0x0800) { op_BMOD(0x31); break; }
|
|
if ((first_opcode&0x0FC0)==0x0840) { op_BMOD(0x21); break; }
|
|
if ((first_opcode&0x0FC0)==0x0880) { op_BMOD(0x11); break; }
|
|
if ((first_opcode&0x0FC0)==0x08C0) { op_BMOD(0x01); break; }
|
|
if ((first_opcode&0x0138)==0x0108) { op_MOVEP(); break; }
|
|
if ((first_opcode&0x0F00)==0x0A00) { op_BOOL_I(3); break; }
|
|
if ((first_opcode&0x0F00)==0x0000) { op_BOOL_I(1); break; }
|
|
if ((first_opcode&0x0F00)==0x0200) { op_BOOL_I(2); break; }
|
|
if ((first_opcode&0x0F00)==0x0400) { op_ADDSUBI(0); break; }
|
|
if ((first_opcode&0x0F00)==0x0600) { op_ADDSUBI(1); break; }
|
|
if ((first_opcode&0x0F00)==0x0C00) { op_BOOL_I(4); break; }
|
|
if ((first_opcode&0x01C0)==0x0100) { op_BMOD(0x30); break; }
|
|
if ((first_opcode&0x01C0)==0x0140) { op_BMOD(0x20); break; }
|
|
if ((first_opcode&0x01C0)==0x0180) { op_BMOD(0x10); break; }
|
|
if ((first_opcode&0x01C0)==0x01C0) { op_BMOD(0x00); break; }
|
|
Exception_Handler(4);
|
|
break;
|
|
|
|
case (0x1000): case (0x2000): case (0x3000):
|
|
{ op_MOVE(); break; }
|
|
|
|
|
|
case (0x4000):
|
|
if ((first_opcode&0x0FC0)==0x00C0) { op_MOVE_FROM_SR(); break; }
|
|
if ((first_opcode&0x0FC0)==0x04C0) { op_MOVE_TO_CCR(); break; }
|
|
if ((first_opcode&0x0FC0)==0x06C0) { op_MOVE_TO_SR(); break; }
|
|
if ((first_opcode&0x0F00)==0x0000) { op_NEGS(3); break; }
|
|
if ((first_opcode&0x0F00)==0x0200) { op_NEGS(4); break; }
|
|
if ((first_opcode&0x0F00)==0x0400) { op_NEGS(2); break; }
|
|
if ((first_opcode&0x0F00)==0x0600) { op_NEGS(1); break; }
|
|
if ((first_opcode&0x0FB8)==0x0880) { op_EXT(); break; }
|
|
if ((first_opcode&0x0FC0)==0x0800) { op_NBCD(); break; }
|
|
if ((first_opcode&0x0FF8)==0x0840) { op_SWAP(); break; }
|
|
if ((first_opcode&0x0FC0)==0x0840) { op_PEA(); break; }
|
|
if ((first_opcode&0x0FFF)==0x0AFC) { Exception_Handler(4); break; }
|
|
if ((first_opcode&0x0FC0)==0x0AC0) { op_TAS(); break; }
|
|
if ((first_opcode&0x0F00)==0x0A00) { op_TST(); break; }
|
|
if ((first_opcode&0x0FF0)==0x0E40) { op_TRAP(); break; }
|
|
if ((first_opcode&0x0FF8)==0x0E50) { op_LINK(); break; }
|
|
if ((first_opcode&0x0FF8)==0x0E58) { op_UNLK(); break; }
|
|
if ((first_opcode&0x0FF0)==0x0E60) { op_MOVE_USP(); break; }
|
|
if ((first_opcode&0x0FFF)==0x0E71) { /* Do Nothing */ break; }
|
|
if ((first_opcode&0x0FFF)==0x0E70) { op_RESET(); break; }
|
|
if ((first_opcode&0x0FFF)==0x0E72) { op_STOP(); break; }
|
|
if ((first_opcode&0x0FFF)==0x0E73) { op_RTE(); break; }
|
|
if ((first_opcode&0x0FFF)==0x0E75) { op_RTS(); break; }
|
|
if ((first_opcode&0x0FFF)==0x0E76) { op_TRAPV(); break; }
|
|
if ((first_opcode&0x0FFF)==0x0E77) { op_RTR(); break; }
|
|
if ((first_opcode&0x0FC0)==0x0E80) { op_JSR(); break; }
|
|
if ((first_opcode&0x0FC0)==0x0EC0) { op_JMP(); break; }
|
|
if ((first_opcode&0x0B80)==0x0880) { op_MOVEM(); break; }
|
|
if ((first_opcode&0x01C0)==0x01C0) { op_LEA(); break; }
|
|
if ((first_opcode&0x01C0)==0x0180) { op_CHK(); break; }
|
|
Exception_Handler(4);
|
|
break;
|
|
|
|
case (0x5000):
|
|
if ((first_opcode&0x00F8)==0x00C8) { op_dBCC(); break; }
|
|
if ((first_opcode&0x00C0)==0x00C0) { op_SCC(); break; }
|
|
if ((first_opcode&0x0100)==0x0000) { op_ADDSUBQ(1); break; }
|
|
if ((first_opcode&0x0100)==0x0100) { op_ADDSUBQ(0); break; }
|
|
Exception_Handler(4);
|
|
break;
|
|
|
|
case (0x6000):
|
|
if ((first_opcode&0x0F00)==0x0100) { op_BSR(); break; }
|
|
if ((first_opcode&0x0000)==0x0000) { op_BCC(); break; }
|
|
Exception_Handler(4);
|
|
break;
|
|
|
|
case (0x7000):
|
|
if ((first_opcode&0x0100)==0x0000) { op_MOVEQ(); break; }
|
|
Exception_Handler(4);
|
|
break;
|
|
|
|
case (0x8000):
|
|
if ((first_opcode&0x01C0)==0x00C0) { op_DIVU(); break; }
|
|
if ((first_opcode&0x01C0)==0x01C0) { op_DIVS(); break; }
|
|
if ((first_opcode&0x01F0)==0x0100) { op_xBCD(1); break; }
|
|
if ((first_opcode&0x0000)==0x0000) { op_BOOL(1); break; }
|
|
Exception_Handler(4);
|
|
break;
|
|
|
|
case (0x9000):
|
|
if ((first_opcode&0x00C0)==0x00C0) { op_ADDSUBA(0); break; }
|
|
if ((first_opcode&0x0130)==0x0100) { op_ADDSUBX(0); break; }
|
|
if ((first_opcode&0x0000)==0x0000) { op_ADDSUB(0); break; }
|
|
Exception_Handler(4);
|
|
break;
|
|
|
|
case (0xA000): { Exception_Handler(10); break; }
|
|
|
|
case (0xB000):
|
|
if ((first_opcode&0x00C0)==0x00C0) { op_CMPA(); break; }
|
|
if ((first_opcode&0x0138)==0x0108) { op_CMPM(); break; }
|
|
if ((first_opcode&0x0100)==0x0100) { op_BOOL(3); break; }
|
|
if ((first_opcode&0x0100)==0x0000) { op_BOOL(4); break; }
|
|
Exception_Handler(4);
|
|
break;
|
|
|
|
case (0xC000):
|
|
if ((first_opcode&0x01C0)==0x00C0) { op_MULU(); break; }
|
|
if ((first_opcode&0x01C0)==0x01C0) { op_MULS(); break; }
|
|
if ((first_opcode&0x01F0)==0x0100) { op_xBCD(0); break; }
|
|
if ((first_opcode&0x0130)==0x0100) { op_EXG(); break; }
|
|
if ((first_opcode&0x0000)==0x0000) { op_BOOL(2); break; }
|
|
Exception_Handler(4);
|
|
break;
|
|
|
|
case (0xD000):
|
|
if ((first_opcode&0x00C0)==0x00C0) { op_ADDSUBA(1); break; }
|
|
if ((first_opcode&0x0130)==0x0100) { op_ADDSUBX(1); break; }
|
|
if ((first_opcode&0x0000)==0x0000) { op_ADDSUB(1); break; }
|
|
Exception_Handler(4);
|
|
break;
|
|
|
|
case (0xE000):
|
|
if ((first_opcode&0x0FC0)==0x01C0) { op_xSL(0,1); break; } // MEMORY Left
|
|
if ((first_opcode&0x0FC0)==0x03C0) { op_xSL(0,2); break; }
|
|
if ((first_opcode&0x0FC0)==0x05C0) { op_ROXL(0); break; }
|
|
if ((first_opcode&0x0FC0)==0x07C0) { op_ROL(0); break; }
|
|
|
|
if ((first_opcode&0x0FC0)==0x00C0) { op_xSR(1,2); break; } // MEMORY Right
|
|
if ((first_opcode&0x0FC0)==0x02C0) { op_xSR(2,2); break; }
|
|
if ((first_opcode&0x0FC0)==0x04C0) { op_ROXR(0); break; }
|
|
if ((first_opcode&0x0FC0)==0x06C0) { op_ROR(0); break; }
|
|
|
|
if ((first_opcode&0x0118)==0x0100) { op_xSL(1,1); break; } // REGISTER Left
|
|
if ((first_opcode&0x0118)==0x0108) { op_xSL(1,2); break; }
|
|
if ((first_opcode&0x0118)==0x0110) { op_ROXL(1); break; }
|
|
if ((first_opcode&0x0118)==0x0118) { op_ROL(1); break; }
|
|
|
|
if ((first_opcode&0x0118)==0x0000) { op_xSR(1,1); break; } // REGISTER Right
|
|
if ((first_opcode&0x0118)==0x0008) { op_xSR(2,1); break; }
|
|
if ((first_opcode&0x0118)==0x0010) { op_ROXR(1); break; }
|
|
if ((first_opcode&0x0118)==0x0018) { op_ROR(1); break; }
|
|
Exception_Handler(4);
|
|
break;
|
|
|
|
case (0xF000): { Exception_Handler(11); break; }
|
|
|
|
default: ;
|
|
}
|
|
|
|
}
|
|
|
|
// Process Trace if flag is set, but don't allow if last opcode caused ILLEGAL or PRIVILEGE exception
|
|
// Also don't allow Trace if it was just set/restored. This allows one instruction to be executed between Traces
|
|
//
|
|
if ( (last_mc68k_flag_T==1 && mc68k_flag_T==1) && last_exception!=4 && last_exception!=8) { clock_counter=6; Exception_Handler(9); }
|
|
else { last_exception = 0; } // Debounce
|
|
|
|
last_mc68k_flag_T = mc68k_flag_T;
|
|
|
|
|
|
}
|
|
|
|
}
|