Add the non functional and the very first version of Emu48 for Android!

This commit is contained in:
dgis 2018-11-12 22:31:04 +00:00
commit 5e6e3f2808
97 changed files with 43324 additions and 0 deletions

11
.gitignore vendored Normal file
View file

@ -0,0 +1,11 @@
*.iml
.gradle
/local.properties
/.idea/caches/build_file_checksums.ser
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
.DS_Store
/build
/captures
.externalNativeBuild

1
app/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

46
app/CMakeLists.txt Normal file
View file

@ -0,0 +1,46 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
#src/main/cpp/native-lib.cpp
src/main/cpp/emu48-jni.c
)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib})

39
app/build.gradle Normal file
View file

@ -0,0 +1,39 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.regis.cosnier.emu48"
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:design:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

21
app/proguard-rules.pro vendored Normal file
View file

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View file

@ -0,0 +1,26 @@
package com.regis.cosnier.emu48;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.regis.cosnier.emu48", appContext.getPackageName());
}
}

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.regis.cosnier.emu48">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -0,0 +1,2 @@
;01477:6300; disable 10 min auto off (internal, undocumented)
017A6:81B1; =makebeep

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,935 @@
Global
Print "=========================================================="
Print ""
Print "This Real 48GX graphic is by Eric Rechlin."
Print "eric@hpcalc.org http://www.hpcalc.org"
Print "Graphic based on a scan by Hewlett-Packard."
Print ""
Print "Note that contrast support, a touch-sensitive"
Print "screen, and hidden NXT and PREV buttons to the"
Print "right and left of the menu are implemented."
Print ""
Print "=========================================================="
Title "Eric's Real 48GX for 800x600"
Author "Eric Rechlin"
Model "G"
Rom "ROM.48G"
Patch "BEEP.48"
Bitmap "REAL48GX.BMP"
Debug 0
End
Background
Offset 0 0
Size 300 531
End
Lcd
Zoom 2
Offset 19 24
Color 0 112 157 114
Color 1 112 157 114
Color 2 104 145 106
Color 3 94 131 95
Color 4 85 119 86
Color 5 76 106 77
Color 6 66 92 67
Color 8 57 79 58
Color 9 48 67 49
Color 10 38 53 38
Color 11 29 40 29
Color 12 20 28 20
Color 13 10 13 10
Color 14 0 0 0
Color 15 0 0 0
Color 16 0 0 0
Color 17 0 0 0
Color 18 0 0 0
Color 19 0 0 0
Color 20 0 0 0
Color 21 0 0 0
Color 22 0 0 0
Color 23 0 0 0
Color 24 0 0 0
Color 25 0 0 0
Color 26 0 0 0
Color 27 0 0 0
Color 28 0 0 0
Color 29 0 0 0
Color 30 0 0 0
Color 31 0 0 0
Color 47 112 157 114
Color 48 104 145 106
Color 49 94 131 95
Color 50 85 119 86
Color 51 76 106 77
Color 52 66 92 67
Color 53 57 79 58
Color 54 48 67 49
Color 55 38 53 38
Color 56 29 40 29
Color 57 20 28 20
Color 58 10 13 10
Color 59 0 0 0
Color 60 0 0 0
Color 61 0 0 0
Color 62 0 0 0
Color 63 0 0 0
End
Annunciator 1
Size 16 11
Offset 32 11
Down 0 531
End
Annunciator 2
Size 16 11
Offset 75 11
Down 16 531
End
Annunciator 3
Size 16 11
Offset 121 11
Down 32 531
End
Annunciator 4
Size 16 11
Offset 163 11
Down 48 531
End
Annunciator 5
Size 16 11
Offset 207 11
Down 64 531
End
Annunciator 6
Size 16 11
Offset 253 11
Down 80 531
End
Button 11
Type 5
Size 38 26
Offset 10 168
OutIn 1 16
End
Button 12
Type 5
Size 38 26
Offset 59 168
OutIn 8 16
End
Button 13
Type 5
Size 38 26
Offset 107 168
OutIn 8 8
End
Button 14
Type 5
Size 38 26
Offset 156 168
OutIn 8 4
End
Button 15
Type 5
Size 38 26
Offset 204 168
OutIn 8 2
End
Button 16
Type 5
Size 38 26
Offset 252 168
OutIn 8 1
End
Button 21
Type 5
Size 38 30
Offset 10 205
OutIn 2 16
End
Button 22
Type 5
Size 38 30
Offset 59 205
OutIn 7 16
End
Button 23
Type 5
Size 38 30
Offset 107 205
OutIn 7 8
End
Button 24
Type 5
Size 38 30
Offset 156 205
OutIn 7 4
End
Button 25
Type 5
Size 38 30
Offset 204 205
OutIn 7 2
End
Button 26
Type 5
Size 38 30
Offset 252 205
OutIn 7 1
End
Button 31
Type 5
Size 38 30
Offset 10 245
OutIn 0 16
End
Button 32
Type 5
Size 38 30
Offset 59 245
OutIn 6 16
End
Button 33
Type 5
Size 38 30
Offset 107 245
OutIn 6 8
End
Button 34
Type 5
Size 38 30
Offset 156 245
OutIn 6 4
End
Button 35
Type 5
Size 38 30
Offset 204 245
OutIn 6 2
End
Button 36
Type 5
Size 38 30
Offset 252 245
OutIn 6 1
End
Button 41
Type 5
Size 38 30
Offset 10 287
OutIn 3 16
End
Button 42
Type 5
Size 38 30
Offset 59 287
OutIn 5 16
End
Button 43
Type 5
Size 38 30
Offset 107 287
OutIn 5 8
End
Button 44
Type 5
Size 38 30
Offset 156 287
OutIn 5 4
End
Button 45
Type 5
Size 38 30
Offset 204 287
OutIn 5 2
End
Button 46
Type 5
Size 38 30
Offset 252 287
OutIn 5 1
End
Button 51
Type 5
Size 87 30
Offset 10 327
OutIn 4 16
End
Button 52
Type 5
Size 38 30
Offset 107 327
OutIn 4 8
End
Button 53
Type 5
Size 38 30
Offset 156 327
OutIn 4 4
End
Button 54
Type 5
Size 38 30
Offset 204 327
OutIn 4 2
End
Button 55
Type 5
Size 38 30
Offset 252 327
OutIn 4 1
End
Button 61
Type 5
Size 38 30
Offset 10 369
OutIn 3 32
End
Button 62
Type 5
Size 48 28
Offset 65 369
OutIn 3 8
End
Button 63
Type 5
Size 48 28
Offset 124 369
OutIn 3 4
End
Button 64
Type 5
Size 48 28
Offset 183 369
OutIn 3 2
End
Button 65
Type 5
Size 48 28
Offset 243 369
OutIn 3 1
End
Button 71
Type 5
Size 38 30
Offset 10 411
OutIn 2 32
End
Button 72
Type 5
Size 48 28
Offset 65 411
OutIn 2 8
End
Button 73
Type 5
Size 48 28
Offset 124 411
OutIn 2 4
End
Button 74
Type 5
Size 48 28
Offset 183 411
OutIn 2 2
End
Button 75
Type 5
Size 48 28
Offset 243 411
OutIn 2 1
End
Button 81
Type 5
Size 38 30
Offset 10 453
OutIn 1 32
End
Button 82
Type 5
Size 48 28
Offset 65 453
OutIn 1 8
End
Button 83
Type 5
Size 48 28
Offset 124 453
OutIn 1 4
End
Button 84
Type 5
Size 48 28
Offset 183 453
OutIn 1 2
End
Button 85
Type 5
Size 48 28
Offset 243 453
OutIn 1 1
End
Button 91
Type 5
Size 38 30
Offset 10 494
OutIn 0 32768
End
Button 92
Type 5
Size 48 28
Offset 65 494
OutIn 0 8
End
Button 93
Type 5
Size 48 28
Offset 124 494
OutIn 0 4
End
Button 94
Type 5
Size 48 28
Offset 183 494
OutIn 0 2
End
Button 95
Type 5
Size 48 28
Offset 243 494
OutIn 0 1
End
Button 101
Type 3
Size 42 14
Offset 19 138
Virtual
OnDown
Press 11
End
OnUp
Release 11
End
End
Button 102
Type 3
Size 42 14
Offset 63 138
Virtual
OnDown
Press 12
End
OnUp
Release 12
End
End
Button 103
Type 3
Size 42 14
Offset 107 138
Virtual
OnDown
Press 13
End
OnUp
Release 13
End
End
Button 104
Type 3
Size 42 14
Offset 151 138
Virtual
OnDown
Press 14
End
OnUp
Release 14
End
End
Button 105
Type 3
Size 42 14
Offset 195 138
Virtual
OnDown
Press 15
End
OnUp
Release 15
End
End
Button 106
Type 3
Size 42 14
Offset 239 138
Virtual
OnDown
Press 16
End
OnUp
Release 16
End
End
Button 107
Type 5
Size 16 16
Offset 0 137
Virtual
OnDown
Press 71
Press 26
End
OnUp
Release 26
Release 71
End
End
Button 108
Type 5
Size 16 16
Offset 284 137
Virtual
OnDown
Press 26
End
OnUp
Release 26
End
End
Button 109
Type 4
Size 262 112
Offset 19 24
Down 19 24
NoHold
End
Scancode 8
Map 8 55
End
Scancode 13
Map 13 51
End
Scancode 16
IfPressed 16
SetFlag 0
Else
ResetFlag 0
End
End
Scancode 17
IfPressed 17
SetFlag 1
Else
ResetFlag 1
End
End
Scancode 27
Map 27 91
End
Scancode 32
Map 32 94
End
Scancode 37
Map 37 34
End
Scancode 38
Map 38 25
End
Scancode 39
Map 39 36
End
Scancode 40
Map 40 35
End
Scancode 45
Map 45 71
End
Scancode 46
Map 46 81
End
Scancode 48
Map 48 92
End
Scancode 49
IfFlag 0
Map 49 71
Map 49 54
Else
Map 49 82
End
End
Scancode 50
Map 50 83
End
Scancode 51
IfFlag 0
Map 51 81
Map 51 65
Else
Map 51 84
End
End
Scancode 52
Map 52 72
End
Scancode 53
Map 53 73
End
Scancode 54
Map 54 74
End
Scancode 55
Map 55 62
End
Scancode 56
IfFlag 0
Map 56 75
Else
Map 56 63
End
End
Scancode 57
IfFlag 0
Map 57 71
Map 57 65
Else
Map 57 64
End
End
Scancode 65
Map 65 11
End
Scancode 66
Map 66 12
End
Scancode 67
Map 67 13
End
Scancode 68
Map 68 14
End
Scancode 69
Map 69 15
End
Scancode 70
Map 70 16
End
Scancode 71
Map 71 21
End
Scancode 72
Map 72 22
End
Scancode 73
Map 73 23
End
Scancode 74
Map 74 24
End
Scancode 75
Map 75 25
End
Scancode 76
Map 76 26
End
Scancode 77
Map 77 31
End
Scancode 78
IfFlag 1
MenuItem 1
Else
Map 78 32
End
End
Scancode 79
Map 79 33
End
Scancode 80
Map 80 34
End
Scancode 81
Map 81 35
End
Scancode 82
Map 82 36
End
Scancode 83
Map 83 41
End
Scancode 84
Map 84 42
End
Scancode 85
Map 85 43
End
Scancode 86
Map 86 44
End
Scancode 87
Map 87 45
End
Scancode 88
Map 88 46
End
Scancode 89
Map 89 52
End
Scancode 90
Map 90 53
End
Scancode 96
Map 96 92
End
Scancode 97
Map 97 82
End
Scancode 98
Map 98 83
End
Scancode 99
Map 99 84
End
Scancode 100
Map 100 72
End
Scancode 101
Map 101 73
End
Scancode 102
Map 102 74
End
Scancode 103
Map 103 62
End
Scancode 104
Map 104 63
End
Scancode 105
Map 105 64
End
Scancode 106
Map 106 75
End
Scancode 107
Map 107 95
End
Scancode 109
Map 109 85
End
Scancode 110
Map 110 93
End
Scancode 111
Map 111 65
End
Scancode 144
IfPressed 144
NotFlag 3
End
End
Scancode 186
IfFlag 0
Map 186 81
Map 186 95
End
End
Scancode 188
IfFlag 0
Map 188 71
Else
Map 188 71
Map 188 93
End
End
Scancode 190
IfFlag 0
Map 190 81
Else
Map 190 93
End
End
Scancode 191
IfFlag 0
Map 191 71
Map 191 55
Else
Map 191 65
End
End
Scancode 192
IfFlag 0
IfPressed 192
NotFlag 2
IfFlag 2
Press 61
Else
Release 61
End
End
Else
Map 192 61
End
End
Scancode 219
IfFlag 0
Map 219 71
Map 219 95
Else
Map 219 71
Map 219 75
End
End
Scancode 220
Map 220 54
End
Scancode 222
IfFlag 0
Map 222 81
Map 222 85
Else
Map 222 31
End
End

View file

@ -0,0 +1,932 @@
Global
Print "=========================================================="
Print ""
Print "This Real 48SX graphic is by Eric Rechlin."
Print "eric@hpcalc.org http://www.hpcalc.org"
Print "Graphic based on a scan by Hewlett-Packard."
Print ""
Print "Note that contrast support, a touch-sensitive"
Print "screen, and hidden NXT and PREV buttons to the"
Print "right and left of the menu are implemented."
Print ""
Print "=========================================================="
Title "Eric's Real 48SX for 800x600"
Author "Eric Rechlin"
Model "S"
Rom "ROM.48S"
Patch "BEEP.48"
Bitmap "REAL48SX.BMP"
Debug 0
End
Background
Offset 0 0
Size 300 531
End
Lcd
Zoom 2
Offset 19 24
Color 0 112 157 114
Color 1 76 106 77
Color 2 66 92 67
Color 3 57 79 58
Color 4 48 67 49
Color 5 38 53 38
Color 6 29 40 29
Color 7 20 28 20
Color 8 10 13 10
Color 9 0 0 0
Color 10 0 0 0
Color 11 0 0 0
Color 12 0 0 0
Color 13 0 0 0
Color 14 0 0 0
Color 15 0 0 0
Color 16 0 0 0
Color 17 0 0 0
Color 18 0 0 0
Color 19 0 0 0
Color 20 0 0 0
Color 21 0 0 0
Color 22 0 0 0
Color 23 0 0 0
Color 24 0 0 0
Color 25 0 0 0
Color 26 0 0 0
Color 43 112 157 114
Color 44 104 145 106
Color 45 94 131 95
Color 46 85 119 86
Color 47 76 106 77
Color 48 66 92 67
Color 49 57 79 58
Color 50 48 67 49
Color 51 38 53 38
Color 52 29 40 29
Color 53 20 28 20
Color 54 10 13 10
Color 55 0 0 0
Color 56 0 0 0
Color 57 0 0 0
Color 58 0 0 0
Color 59 0 0 0
Color 60 0 0 0
End
Annunciator 1
Size 16 11
Offset 32 11
Down 0 531
End
Annunciator 2
Size 16 11
Offset 75 11
Down 16 531
End
Annunciator 3
Size 16 11
Offset 121 11
Down 32 531
End
Annunciator 4
Size 16 11
Offset 163 11
Down 48 531
End
Annunciator 5
Size 16 11
Offset 207 11
Down 64 531
End
Annunciator 6
Size 16 11
Offset 253 11
Down 80 531
End
Button 11
Type 5
Size 38 26
Offset 11 167
OutIn 1 16
End
Button 12
Type 5
Size 38 26
Offset 59 167
OutIn 8 16
End
Button 13
Type 5
Size 38 26
Offset 107 167
OutIn 8 8
End
Button 14
Type 5
Size 38 26
Offset 156 167
OutIn 8 4
End
Button 15
Type 5
Size 38 26
Offset 204 167
OutIn 8 2
End
Button 16
Type 5
Size 38 26
Offset 252 167
OutIn 8 1
End
Button 21
Type 5
Size 38 30
Offset 11 205
OutIn 2 16
End
Button 22
Type 5
Size 38 30
Offset 59 205
OutIn 7 16
End
Button 23
Type 5
Size 38 30
Offset 107 205
OutIn 7 8
End
Button 24
Type 5
Size 38 30
Offset 156 205
OutIn 7 4
End
Button 25
Type 5
Size 38 30
Offset 204 205
OutIn 7 2
End
Button 26
Type 5
Size 38 30
Offset 252 205
OutIn 7 1
End
Button 31
Type 5
Size 38 30
Offset 11 245
OutIn 0 16
End
Button 32
Type 5
Size 38 30
Offset 59 245
OutIn 6 16
End
Button 33
Type 5
Size 38 30
Offset 107 245
OutIn 6 8
End
Button 34
Type 5
Size 38 30
Offset 156 245
OutIn 6 4
End
Button 35
Type 5
Size 38 30
Offset 204 245
OutIn 6 2
End
Button 36
Type 5
Size 38 30
Offset 252 245
OutIn 6 1
End
Button 41
Type 5
Size 38 30
Offset 11 287
OutIn 3 16
End
Button 42
Type 5
Size 38 30
Offset 59 287
OutIn 5 16
End
Button 43
Type 5
Size 38 30
Offset 107 287
OutIn 5 8
End
Button 44
Type 5
Size 38 30
Offset 156 287
OutIn 5 4
End
Button 45
Type 5
Size 38 30
Offset 204 287
OutIn 5 2
End
Button 46
Type 5
Size 38 30
Offset 252 287
OutIn 5 1
End
Button 51
Type 5
Size 87 30
Offset 11 327
OutIn 4 16
End
Button 52
Type 5
Size 38 30
Offset 107 327
OutIn 4 8
End
Button 53
Type 5
Size 38 30
Offset 156 327
OutIn 4 4
End
Button 54
Type 5
Size 38 30
Offset 204 327
OutIn 4 2
End
Button 55
Type 5
Size 38 30
Offset 252 327
OutIn 4 1
End
Button 61
Type 5
Size 38 30
Offset 11 369
OutIn 3 32
End
Button 62
Type 5
Size 48 28
Offset 65 369
OutIn 3 8
End
Button 63
Type 5
Size 48 28
Offset 124 369
OutIn 3 4
End
Button 64
Type 5
Size 48 28
Offset 183 369
OutIn 3 2
End
Button 65
Type 5
Size 48 28
Offset 243 369
OutIn 3 1
End
Button 71
Type 5
Size 38 30
Offset 11 410
OutIn 2 32
End
Button 72
Type 5
Size 48 28
Offset 65 410
OutIn 2 8
End
Button 73
Type 5
Size 48 28
Offset 124 410
OutIn 2 4
End
Button 74
Type 5
Size 48 28
Offset 183 410
OutIn 2 2
End
Button 75
Type 5
Size 48 28
Offset 243 410
OutIn 2 1
End
Button 81
Type 5
Size 38 30
Offset 11 453
OutIn 1 32
End
Button 82
Type 5
Size 48 28
Offset 65 453
OutIn 1 8
End
Button 83
Type 5
Size 48 28
Offset 124 453
OutIn 1 4
End
Button 84
Type 5
Size 48 28
Offset 183 453
OutIn 1 2
End
Button 85
Type 5
Size 48 28
Offset 243 453
OutIn 1 1
End
Button 91
Type 5
Size 38 30
Offset 11 494
OutIn 0 32768
End
Button 92
Type 5
Size 48 28
Offset 65 494
OutIn 0 8
End
Button 93
Type 5
Size 48 28
Offset 124 494
OutIn 0 4
End
Button 94
Type 5
Size 48 28
Offset 183 494
OutIn 0 2
End
Button 95
Type 5
Size 48 28
Offset 243 494
OutIn 0 1
End
Button 101
Type 3
Size 42 14
Offset 19 138
Virtual
OnDown
Press 11
End
OnUp
Release 11
End
End
Button 102
Type 3
Size 42 14
Offset 63 138
Virtual
OnDown
Press 12
End
OnUp
Release 12
End
End
Button 103
Type 3
Size 42 14
Offset 107 138
Virtual
OnDown
Press 13
End
OnUp
Release 13
End
End
Button 104
Type 3
Size 42 14
Offset 151 138
Virtual
OnDown
Press 14
End
OnUp
Release 14
End
End
Button 105
Type 3
Size 42 14
Offset 195 138
Virtual
OnDown
Press 15
End
OnUp
Release 15
End
End
Button 106
Type 3
Size 42 14
Offset 239 138
Virtual
OnDown
Press 16
End
OnUp
Release 16
End
End
Button 107
Type 5
Size 16 16
Offset 0 137
Virtual
OnDown
Press 71
Press 26
End
OnUp
Release 26
Release 71
End
End
Button 108
Type 5
Size 16 16
Offset 284 137
Virtual
OnDown
Press 26
End
OnUp
Release 26
End
End
Button 109
Type 4
Size 262 112
Offset 19 24
Down 19 24
NoHold
End
Scancode 8
Map 8 55
End
Scancode 13
Map 13 51
End
Scancode 16
IfPressed 16
SetFlag 0
Else
ResetFlag 0
End
End
Scancode 17
IfPressed 17
SetFlag 1
Else
ResetFlag 1
End
End
Scancode 27
Map 27 91
End
Scancode 32
Map 32 94
End
Scancode 37
Map 37 34
End
Scancode 38
Map 38 25
End
Scancode 39
Map 39 36
End
Scancode 40
Map 40 35
End
Scancode 45
Map 45 71
End
Scancode 46
Map 46 81
End
Scancode 48
Map 48 92
End
Scancode 49
IfFlag 0
Map 49 71
Map 49 54
Else
Map 49 82
End
End
Scancode 50
Map 50 83
End
Scancode 51
IfFlag 0
Map 51 81
Map 51 65
Else
Map 51 84
End
End
Scancode 52
Map 52 72
End
Scancode 53
Map 53 73
End
Scancode 54
Map 54 74
End
Scancode 55
Map 55 62
End
Scancode 56
IfFlag 0
Map 56 75
Else
Map 56 63
End
End
Scancode 57
IfFlag 0
Map 57 71
Map 57 65
Else
Map 57 64
End
End
Scancode 65
Map 65 11
End
Scancode 66
Map 66 12
End
Scancode 67
Map 67 13
End
Scancode 68
Map 68 14
End
Scancode 69
Map 69 15
End
Scancode 70
Map 70 16
End
Scancode 71
Map 71 21
End
Scancode 72
Map 72 22
End
Scancode 73
Map 73 23
End
Scancode 74
Map 74 24
End
Scancode 75
Map 75 25
End
Scancode 76
Map 76 26
End
Scancode 77
Map 77 31
End
Scancode 78
IfFlag 1
MenuItem 1
Else
Map 78 32
End
End
Scancode 79
Map 79 33
End
Scancode 80
Map 80 34
End
Scancode 81
Map 81 35
End
Scancode 82
Map 82 36
End
Scancode 83
Map 83 41
End
Scancode 84
Map 84 42
End
Scancode 85
Map 85 43
End
Scancode 86
Map 86 44
End
Scancode 87
Map 87 45
End
Scancode 88
Map 88 46
End
Scancode 89
Map 89 52
End
Scancode 90
Map 90 53
End
Scancode 96
Map 96 92
End
Scancode 97
Map 97 82
End
Scancode 98
Map 98 83
End
Scancode 99
Map 99 84
End
Scancode 100
Map 100 72
End
Scancode 101
Map 101 73
End
Scancode 102
Map 102 74
End
Scancode 103
Map 103 62
End
Scancode 104
Map 104 63
End
Scancode 105
Map 105 64
End
Scancode 106
Map 106 75
End
Scancode 107
Map 107 95
End
Scancode 109
Map 109 85
End
Scancode 110
Map 110 93
End
Scancode 111
Map 111 65
End
Scancode 144
IfPressed 144
NotFlag 3
End
End
Scancode 186
IfFlag 0
Map 186 81
Map 186 95
End
End
Scancode 188
IfFlag 0
Map 188 71
Else
Map 188 71
Map 188 93
End
End
Scancode 190
IfFlag 0
Map 190 81
Else
Map 190 93
End
End
Scancode 191
IfFlag 0
Map 191 71
Map 191 55
Else
Map 191 65
End
End
Scancode 192
IfFlag 0
IfPressed 192
NotFlag 2
IfFlag 2
Press 61
Else
Release 61
End
End
Else
Map 192 61
End
End
Scancode 219
IfFlag 0
Map 219 71
Map 219 95
Else
Map 219 71
Map 219 75
End
End
Scancode 220
Map 220 54
End
Scancode 222
IfFlag 0
Map 222 81
Map 222 85
Else
Map 222 31
End
End

415
app/src/main/cpp/APPLE.C Normal file
View file

@ -0,0 +1,415 @@
/*
* apple.c
*
* This file is part of Emu48
*
* Copyright (C) 2005 CdB for HP
* Copyright (C) 2006 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
#include "Opcodes.h"
#include "apple.h"
#include "io.h" // I/O register definitions
#include "i28f160.h"
#define w Chipset
#define _KB(s) ((s) * 1024 * 2)
#pragma intrinsic(memset,memcpy)
#include "Ops.h"
//
// ROM buffer access functions
//
static __inline void WrDirtyPage(DWORD d)
{
if (pbyRomDirtyPage) // using dirty ROM page table
{
DWORD dwPage = d / ROMPAGESIZE; // this is the page
_ASSERT(dwPage < dwRomDirtyPageSize);
pbyRomDirtyPage[dwPage] = TRUE; // page is dirty
}
return;
}
static __inline void EraseBlock(DWORD d,DWORD dwNibSize)
{
LPBYTE pbyAddr = pbyRom + d;
while (dwNibSize--)
{
WrDirtyPage(d++); // make page dirty
*pbyAddr++ = 0x0F; // clear address
}
return;
}
static CONST LPBYTE ppReg[] = { w.A, w.B, w.C, w.D };
static QWORD DecodeReg64(LPBYTE R, BYTE byNF)
{
QWORD qwVal = Npack64(R,16); // generate 64bit number from register
switch (byNF) // field selector
{
case 0: return (qwVal >> (w.P*4)) & 0xf; // P
case 1: return qwVal & ~((QWORD)~0 << ((w.P+1)*4));// WP
case 2: return (qwVal >> 8) & 0xf; // XS
case 3: return qwVal & 0xfff; // X
case 4: return (qwVal >> 60) & 0xf; // S
case 5: return (qwVal >> 12) & 0x0000ffffffffffff; // M
case 6: return qwVal & 0xff; // B
case 7: return qwVal; // W
case 15: return qwVal & 0xfffff; // A
// default: return qwVal & w.fld[byNF-8]; // F1-F7
default: return qwVal;
}
}
static void EncodeReg64(QWORD v, LPBYTE R, BYTE byNF)
{
if (byNF > 7 && byNF < 15) // user mask area F1-F7
{
// QWORD qwMask = w.fld[byNF-8]; // F1-F7
// QWORD qwVal = Npack64(R,16); // original content of register
// v = (v & qwMask) | (qwVal & ~qwMask); // mask operation
byNF = 7; // write W area
}
Nunpack64(R+F_s[byNF], v, F_l[byNF]);
return;
}
static QWORD o80BReg164(LPBYTE I)
{
_ASSERT((I[5] & 3) < ARRAYSIZEOF(ppReg));
return DecodeReg64(ppReg[I[5] & 3], I[6]);
}
static QWORD o80BReg264(LPBYTE I)
{
_ASSERT((I[5] >> 2) < ARRAYSIZEOF(ppReg));
return DecodeReg64(ppReg[I[5] >> 2], I[6]);
}
static void o80BRegWrite(QWORD v, LPBYTE I)
{
_ASSERT((I[5] & 3) < ARRAYSIZEOF(ppReg));
EncodeReg64(v, ppReg[I[5] & 3], I[6]);
return;
}
// SETFLDx
VOID o80BF7x(LPBYTE I)
{
QWORD qwVal;
_ASSERT(FALSE); // not tested so far
w.pc+=1; // skip x nibble
qwVal = Npack64(w.C,16); // generate 64bit number from C register
w.carry = (qwVal == 0) // set carry if field mask = 0
|| (I[5] < 8) || (I[5] > 14); // or x argument not in range 8..15
if (!w.carry) // field mask and argument are valid
{
_ASSERT(I[5] >= 8 && I[5] <= 14);
// w.fld[I[5]-8] = qwVal;
}
return;
}
// RPL2 (normal LOOP with preserving Carry)
VOID o80B00(VOID)
{
BYTE p[5];
Nread(w.A, w.d0, 5); // A=DAT0 A
w.d0 = (w.d0 + 5) & 0xFFFFF; // D0=D0+ 5
Nread(p, Npack(w.A,5), 5); // PC=(A)
w.pc = Npack(p,5);
return;
}
// FALSE +5
VOID o80B30(VOID)
{
Ndec(w.D, 5, 0); // D=D-1 A
if (w.carry) w.pc = 0x03A9B; // memerr?
w.d1 -= 5; // D1=D1- 5 (don't care about carry here)
Nwrite(w.A, w.d1, 5); // DAT1=A A
o80B00(); // LOOP
return;
}
// DOFALSE
VOID o80B40(VOID)
{
w.P = 0; // P= 0
PCHANGED;
Nunpack(w.C,0x03AC0,5); // LC(5) =FALSE
memcpy(w.A, w.C, 5); // A=C A
o80B30(); // PC=(A) (call FALSE)
return;
}
// MOVEDOWN
VOID o80B60(VOID)
{
BYTE byData[16];
DWORD dwC,s;
for (dwC = Npack(w.C,5); dwC > 0; dwC -= s)
{
s = ARRAYSIZEOF(byData); // max size for data
if (dwC < s) s = dwC;
Npeek(byData,w.d0,s); // read source without CRC update
Nwrite(byData,w.d1,s); // write destination
w.d0 = (w.d0 + s) & 0xFFFFF;
w.d1 = (w.d1 + s) & 0xFFFFF;
}
w.P = 0;
PCHANGED;
w.carry = FALSE;
return;
}
// MOVEUP
VOID o80B70(VOID)
{
BYTE byData[16];
DWORD dwC,s;
for (dwC = Npack(w.C,5); dwC > 0; dwC -= s)
{
s = ARRAYSIZEOF(byData); // max size for data
if (dwC < s) s = dwC;
w.d0 = (w.d0 - s) & 0xFFFFF;
w.d1 = (w.d1 - s) & 0xFFFFF;
Npeek(byData,w.d0,s); // read source without CRC update
Nwrite(byData,w.d1,s); // write destination
}
w.P = 0;
PCHANGED;
w.carry = FALSE;
return;
}
// CREATETEMP
VOID o80B80(VOID)
{
DWORD dwC,dwAddress;
dwC = Npack(w.C,5); // desired size of hole
dwAddress = RPL_CreateTemp(dwC,FALSE); // allocate memory
if (dwAddress)
{
w.d0 = dwAddress; // object position
w.d1 = (w.d0 + dwC) & 0xFFFFF; // link field of hole
w.carry = FALSE; // no error
}
else
{
w.carry = TRUE; // error
}
dwC += 6; // desired size + link field
Nunpack(w.B,dwC,5); // B[A] = size + 6
Nunpack(w.C,dwC,5); // C[A] = size + 6
return;
}
// setup basic memory configuration
VOID o80B04(VOID)
{
DWORD a;
a = Npack(w.C,5); // save C[A]
Reset(); // unconfig all devices
Nunpack(w.C,0x100,5); // IO: 0x00100
Config(); // addr
Nunpack(w.C,0x80000,5); // RAM: 0x80000 size 256KB
Config(); // size
Config(); // addr
Nunpack(w.C,a,5); // restore C[A]
w.P = 0;
PCHANGED;
return;
}
// erase flash bank
VOID o80B14(VOID)
{
DWORD dwStart,dwStop;
BYTE byBank = w.C[15]; // C[S] = bank to erase
_ASSERT(FALSE); // not tested so far
// ROM is logically organized in 16 banks with 128KB
dwStart = byBank * _KB(128); // start address
dwStop = dwStart + _KB(128); // last address
if (byBank == 0) dwStart += _KB(64); // skip boot loader
// clear bank
EraseBlock(dwStart,dwStop-dwStart);
w.carry = FALSE; // no error
return;
}
// write bytes to flash
VOID o80B24(VOID)
{
LPBYTE pbyBuffer;
DWORD dwNib,dwAddr,dwSize;
dwNib = Npack(w.C,5) * 2; // no. of nibbles to copy
dwAddr = FlashROMAddr(w.d1); // linear addr in flash chip
dwSize = dwRomSize - dwAddr; // remaining memory size in flash
if (dwNib > dwSize) dwNib = dwSize; // prevent buffer overflow
pbyBuffer = (LPBYTE) malloc(dwNib); // allocate data buffer
if (pbyBuffer != NULL)
{
DWORD i;
Npeek(pbyBuffer,w.d0,dwNib); // get data
for (i = 0; i < dwNib; ++i)
{
WrDirtyPage(dwAddr); // make page dirty
pbyRom[dwAddr++] = pbyBuffer[i]; // write data
}
free(pbyBuffer);
}
w.d0 += dwNib; // update source register
w.d1 += dwNib; // update destination register
w.carry = FALSE; // no error
return;
}
// OUTBYT
VOID o80B65(VOID)
{
// set Transmitting annunciator
BYTE byAnn = w.IORam[ANNCTRL+1] | 0x2;
WriteIO(&byAnn,ANNCTRL+1,1);
SendByteUdp((BYTE) Npack(w.A,2)); // send data byte
w.P = 0;
PCHANGED;
w.carry = FALSE; // no error
return;
}
// CdB for HP: add apples BUSCC commands
VOID o80BExt(LPBYTE I) // Saturnator extentions
{
DWORD a;
w.pc+=2;
switch (I[3]+(I[4]<<4))
{
case 0x00: o80B00(); break; // RPL2 (preserve Carry)
case 0x03: o80B30(); break; // FALSE
case 0x04: o80B40(); break; // DOFALSE
case 0x05: External(&w); PCHANGED; break; // BEEP2 implemented using Emu48's beep
case 0x06: o80B60(); break; // MOVEDOWN
case 0x07: o80B70(); break; // MOVEUP
case 0x08: o80B80(); break; // CREATETEMP
case 0x09: RCKBp(&w); PCHANGED; break; // RCKBp
case 0x0A: break; // KEYDN not implemented
case 0x0B: break; // no doslow implemented
case 0x10: // simulate off function
{
BOOL bShutdn = TRUE; // shut down
// only shut down when no timer wake up
if (w.IORam[TIMER1_CTRL]&WKE) // WKE bit of timer1 is set
{
if (ReadT1()&0x08) // and MSB of timer1 is set
{
w.IORam[TIMER1_CTRL] &= ~WKE; // clear WKE
bShutdn = FALSE; // don't shut down
}
}
if (w.IORam[TIMER2_CTRL]&WKE) // WKE bit of timer2 is set
{
if (ReadT2()&0x80000000) // and MSB of timer2 is set
{
w.IORam[TIMER2_CTRL] &= ~WKE; // clear WKE
bShutdn = FALSE; // don't shut down
}
}
if (w.in==0 && bShutdn) // shut down only when enabled
{
w.Shutdn = TRUE; // set mode before exit emulation loop
bInterrupt = TRUE;
}
}
break;
case 0x11: w.pc+=2; break; // do not do gettime, just skip the RTN after it to fall in the normal gettime function (only valid in untouched ROM)
case 0x12: break; // do not do settime, fall in the normal settime function (only valid in untouched ROM)
case 0x13: break; // RESETOS not implemented
case 0x14: break; // AUTOTEST not implemented
case 0x15: break; // NATIVE? not implemented
case 0x17: break; // SERIAL not implemented
case 0x28: w.HST |= I[5]; w.pc+=1; break; // HST=1.x
case 0x29: w.A[4]= w.A[3]= w.A[2]= w.A[0]= 0; if (cCurrentRomType=='Q') w.A[1]=5; else w.A[1]=4; break; // screen height = 0x50 = 80
case 0x2A: w.A[4]= w.A[3]= w.A[2]= 0; w.A[1]=8; w.A[0]=3; break; // screen width = 0x83 = 131
case 0x2B: w.carry = (cCurrentRomType == '2'); break; // it is medium apple
case 0x2C: w.carry = (cCurrentRomType == 'Q'); break; // it is big apple
case 0x2E: w.carry = (nCurrentClass == 50); break; // it is big apple V2
case 0x30: w.d0address= Npack(w.C,5)>>12; Map(0,0xff); break; //config_disp0 Ca:address 4K data
case 0x31: w.d0address=0; Map(0,0xff); RefreshDisp0(); break; //unconfig_disp0 does the refresh
case 0x32: RefreshDisp0(); break; //refresh_disp0 force refresh
case 0x33: a= Npack(w.C,2); if (a>(DWORD)SCREENHEIGHT) a= SCREENHEIGHT; /* w.lcounter = (SCREENHEIGHT-a) */; w.d0size= a; RefreshDisp0(); break; //set_lines_disp0 nb in Cb
case 0x34: w.d0offset= Npack(w.C,5); w.d0offset &= 0x7FF; break; //set_offset_disp0 offset to disp in disp0
case 0x35: Nunpack(w.C,w.d0offset,5); break; // native_get_line_disp0
case 0x38: w.HST |= I[5]; w.pc+=3; break; // ?HST=1.x not implemented
case 0x40: o80B04(); break; // setup basic memory configuration
// case 0x41: o80B14(); break; // erase flash bank
case 0x42: o80B24(); break; // write bytes into flash
// case 0x43: ??? // format flash bank
case 0x50: break; // REMON not implemented
case 0x51: break; // REMOFF not implemented
case 0x56: o80B65(); break; // OUTBYT
case 0x57: w.D[0]= w.D[1]= 0; break;
case 0x60: break; // ACCESSSD not implemented
case 0x61: break; // PORTTAG? not implemented
case 0x64: w.carry = FALSE; break; // no SD card inserted
case 0x66: w.carry = FALSE; break; // simulate format fail card inserted
case 0x7F: w.carry = TRUE; w.pc+=1; break; // SETFLDn not implemented, set carry for failed
case 0x80: { QWORD b = o80BReg264(I); o80BRegWrite(b, I); w.pc+=2; break; } // r=s
case 0x81: { QWORD a = o80BReg164(I); QWORD b = o80BReg264(I); o80BRegWrite(a+b, I); w.pc+=2; break; } // r=r+s
case 0x82: { QWORD a = o80BReg164(I); QWORD b = o80BReg264(I); o80BRegWrite(a-b, I); w.pc+=2; break; } // r=r-s
case 0x83: { QWORD a = o80BReg164(I); QWORD b = o80BReg264(I); o80BRegWrite(a*b, I); w.pc+=2; break; } // r=r*s
case 0x84: { QWORD a = o80BReg164(I); QWORD b = o80BReg264(I); o80BRegWrite(a/b, I); w.pc+=2; break; } // r=r/s
case 0x85: { QWORD a = o80BReg164(I); QWORD b = o80BReg264(I); o80BRegWrite(a%b, I); w.pc+=2; break; } // r=r%s
case 0x86: { QWORD b = o80BReg264(I); o80BRegWrite(~b, I); w.pc+=2; break; } // r=-r-1
case 0x87: { QWORD b = o80BReg264(I); o80BRegWrite((QWORD)(-(__int64)b), I); w.pc+=2; break; } // r=-r
case 0x88: { QWORD a = o80BReg164(I); QWORD b = o80BReg264(I); o80BRegWrite(a<<b, I); w.pc+=2; break; } // r=r<s
case 0x89: { QWORD a = o80BReg164(I); QWORD b = o80BReg264(I); o80BRegWrite(a>>b, I); w.pc+=2; break; } // r=r>s
case 0x8A: { QWORD a = o80BReg164(I); QWORD b = o80BReg264(I); o80BRegWrite(a^b, I); w.pc+=2; break; } // r=r^s
case 0x90: break; // data streamer not implemented
case 0xEE: break; // ARMFLUSH not implemented
case 0xEF: break; // ARMSYS not implemented
case 0xFF: break; // ARMSAT not implemented
default: w.pc-= 2;
}
return;
}

19
app/src/main/cpp/APPLE.H Normal file
View file

@ -0,0 +1,19 @@
/*
* apple.h
*
* This file is part of Emu48
*
* Copyright (C) 2006 Christoph Gießelink
*
*/
extern VOID o80B00(VOID);
extern VOID o80B30(VOID);
extern VOID o80B40(VOID);
extern VOID o80B60(VOID);
extern VOID o80B70(VOID);
extern VOID o80B80(VOID);
extern VOID o80B04(VOID);
extern VOID o80B14(VOID);
extern VOID o80B24(VOID);
extern VOID o80BExt(LPBYTE I); // Saturnator extentions

27
app/src/main/cpp/COLOR.H Normal file
View file

@ -0,0 +1,27 @@
/*
* color.h
*
* This file is part of Emu48
*
* Copyright (C) 1999 Christoph Gießelink
*
*/
#define COLOR_BLACK 0x00000000
#define COLOR_MAROON 0x00000080
#define COLOR_GREEN 0x00008000
#define COLOR_OLIVE 0x00008080
#define COLOR_NAVY 0x00800000
#define COLOR_PURPLE 0x00800080
#define COLOR_TEAL 0x00808000
#define COLOR_GRAY 0x00808080
#define COLOR_SILVER 0x00C0C0C0
#define COLOR_RED 0x000000FF
#define COLOR_LIME 0x0000FF00
#define COLOR_YELLOW 0x0000FFFF
#define COLOR_BLUE 0x00FF0000
#define COLOR_FUCHSIA 0x00FF00FF
#define COLOR_AQUA 0x00FFFF00
#define COLOR_LTGRAY 0x00C0C0C0
#define COLOR_DKGRAY 0x00808080
#define COLOR_WHITE 0x00FFFFFF

89
app/src/main/cpp/CURSOR.C Normal file
View file

@ -0,0 +1,89 @@
/*
* Cursor.c
*
* This file is part of Emu48
*
* Copyright (C) 2004 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
// hand cursor AND mask
static CONST BYTE ANDmaskCursor[] =
{
0xFF, 0xFF, 0xFF, 0xFF, // 1111 1111 1111 1111 1111 1111 1111 1111
0xFF, 0xFF, 0xFF, 0xFF, // 1111 1111 1111 1111 1111 1111 1111 1111
0xFF, 0xFF, 0xFF, 0xFF, // 1111 1111 1111 1111 1111 1111 1111 1111
0xFF, 0xFF, 0xFF, 0xFF, // 1111 1111 1111 1111 1111 1111 1111 1111
0xFF, 0xFF, 0xFF, 0xFF, // 1111 1111 1111 1111 1111 1111 1111 1111
0xFF, 0xF3, 0xFF, 0xFF, // 1111 1111 1111 0011 1111 1111 1111 1111
0xFF, 0xE1, 0xFF, 0xFF, // 1111 1111 1110 0001 1111 1111 1111 1111
0xFF, 0xE1, 0xFF, 0xFF, // 1111 1111 1110 0001 1111 1111 1111 1111
0xFF, 0xE1, 0xFF, 0xFF, // 1111 1111 1110 0001 1111 1111 1111 1111
0xFF, 0xE1, 0xFF, 0xFF, // 1111 1111 1110 0001 1111 1111 1111 1111
0xFF, 0xE0, 0x7F, 0xFF, // 1111 1111 1110 0000 0111 1111 1111 1111
0xFF, 0xE0, 0x0F, 0xFF, // 1111 1111 1110 0000 0000 1111 1111 1111
0xFF, 0xE0, 0x03, 0xFF, // 1111 1111 1110 0000 0000 0011 1111 1111
0xFF, 0xE0, 0x01, 0xFF, // 1111 1111 1110 0000 0000 0001 1111 1111
0xFE, 0x20, 0x00, 0xFF, // 1111 1110 0010 0000 0000 0000 1111 1111
0xFE, 0x00, 0x00, 0xFF, // 1111 1110 0000 0000 0000 0000 1111 1111
0xFE, 0x00, 0x00, 0xFF, // 1111 1110 0000 0000 0000 0000 1111 1111
0xFF, 0x00, 0x00, 0xFF, // 1111 1111 0000 0000 0000 0000 1111 1111
0xFF, 0x80, 0x00, 0xFF, // 1111 1111 1000 0000 0000 0000 1111 1111
0xFF, 0x80, 0x00, 0xFF, // 1111 1111 1000 0000 0000 0000 1111 1111
0xFF, 0xC0, 0x00, 0xFF, // 1111 1111 1100 0000 0000 0000 1111 1111
0xFF, 0xC0, 0x01, 0xFF, // 1111 1111 1100 0000 0000 0001 1111 1111
0xFF, 0xE0, 0x01, 0xFF, // 1111 1111 1110 0000 0000 0001 1111 1111
0xFF, 0xE0, 0x01, 0xFF, // 1111 1111 1110 0000 0000 0001 1111 1111
0xFF, 0xF0, 0x03, 0xFF, // 1111 1111 1111 0000 0000 0011 1111 1111
0xFF, 0xF0, 0x03, 0xFF, // 1111 1111 1111 0000 0000 0011 1111 1111
0xFF, 0xF0, 0x03, 0xFF, // 1111 1111 1111 0000 0000 0011 1111 1111
0xFF, 0xFF, 0xFF, 0xFF, // 1111 1111 1111 1111 1111 1111 1111 1111
0xFF, 0xFF, 0xFF, 0xFF, // 1111 1111 1111 1111 1111 1111 1111 1111
0xFF, 0xFF, 0xFF, 0xFF, // 1111 1111 1111 1111 1111 1111 1111 1111
0xFF, 0xFF, 0xFF, 0xFF, // 1111 1111 1111 1111 1111 1111 1111 1111
0xFF, 0xFF, 0xFF, 0xFF // 1111 1111 1111 1111 1111 1111 1111 1111
};
// hand cursor XOR mask
static CONST BYTE XORmaskCursor[] =
{
0x00, 0x00, 0x00, 0x00, // 0000 0000 0000 0000 0000 0000 0000 0000
0x00, 0x00, 0x00, 0x00, // 0000 0000 0000 0000 0000 0000 0000 0000
0x00, 0x00, 0x00, 0x00, // 0000 0000 0000 0000 0000 0000 0000 0000
0x00, 0x00, 0x00, 0x00, // 0000 0000 0000 0000 0000 0000 0000 0000
0x00, 0x00, 0x00, 0x00, // 0000 0000 0000 0000 0000 0000 0000 0000
0x00, 0x00, 0x00, 0x00, // 0000 0000 0000 0000 0000 0000 0000 0000
0x00, 0x0C, 0x00, 0x00, // 0000 0000 0000 1100 0000 0000 0000 0000
0x00, 0x0C, 0x00, 0x00, // 0000 0000 0000 1100 0000 0000 0000 0000
0x00, 0x0C, 0x00, 0x00, // 0000 0000 0000 1100 0000 0000 0000 0000
0x00, 0x0C, 0x00, 0x00, // 0000 0000 0000 1100 0000 0000 0000 0000
0x00, 0x0C, 0x00, 0x00, // 0000 0000 0000 1100 0000 0000 0000 0000
0x00, 0x0D, 0x80, 0x00, // 0000 0000 0000 1101 1000 0000 0000 0000
0x00, 0x0D, 0xB0, 0x00, // 0000 0000 0000 1101 1011 0000 0000 0000
0x00, 0x0D, 0xB4, 0x00, // 0000 0000 0000 1101 1011 0100 0000 0000
0x00, 0x0D, 0xB6, 0x00, // 0000 0000 0000 1101 1011 0110 0000 0000
0x00, 0xCF, 0xF6, 0x00, // 0000 0000 1100 1111 1111 0110 0000 0000
0x00, 0xEF, 0xFE, 0x00, // 0000 0000 1110 1111 1111 1110 0000 0000
0x00, 0x6F, 0xFE, 0x00, // 0000 0000 0110 1111 1111 1110 0000 0000
0x00, 0x2F, 0xFE, 0x00, // 0000 0000 0010 1111 1111 1110 0000 0000
0x00, 0x3F, 0xFE, 0x00, // 0000 0000 0011 1111 1111 1110 0000 0000
0x00, 0x1F, 0xFE, 0x00, // 0000 0000 0001 1111 1111 1110 0000 0000
0x00, 0x1F, 0xFC, 0x00, // 0000 0000 0001 1111 1111 1100 0000 0000
0x00, 0x0F, 0xFC, 0x00, // 0000 0000 0000 1111 1111 1100 0000 0000
0x00, 0x0F, 0xFC, 0x00, // 0000 0000 0000 1111 1111 1100 0000 0000
0x00, 0x07, 0xF8, 0x00, // 0000 0000 0000 0111 1111 1000 0000 0000
0x00, 0x07, 0xF8, 0x00, // 0000 0000 0000 0111 1111 1000 0000 0000
0x00, 0x00, 0x00, 0x00, // 0000 0000 0000 0000 0000 0000 0000 0000
0x00, 0x00, 0x00, 0x00, // 0000 0000 0000 0000 0000 0000 0000 0000
0x00, 0x00, 0x00, 0x00, // 0000 0000 0000 0000 0000 0000 0000 0000
0x00, 0x00, 0x00, 0x00, // 0000 0000 0000 0000 0000 0000 0000 0000
0x00, 0x00, 0x00, 0x00, // 0000 0000 0000 0000 0000 0000 0000 0000
0x00, 0x00, 0x00, 0x00 // 0000 0000 0000 0000 0000 0000 0000 0000
};
HCURSOR CreateHandCursor(VOID)
{
return CreateCursor(hApp,12,5,32,32,ANDmaskCursor,XORmaskCursor);
}

182
app/src/main/cpp/DDESERV.C Normal file
View file

@ -0,0 +1,182 @@
/*
* DdeServ.c
*
* This file is part of Emu48
*
* Copyright (C) 1998 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
#include "io.h"
HDDEDATA CALLBACK DdeCallback(UINT iType,UINT iFmt,HCONV hConv,
HSZ hsz1,HSZ hsz2,HDDEDATA hData,
DWORD dwData1,DWORD dwData2)
{
TCHAR *psz,szBuffer[32];
HDDEDATA hReturn;
LPBYTE lpData,lpHeader;
DWORD dwAddress,dwSize,dwLoop,dwIndex;
UINT nStkLvl;
BOOL bSuccess;
// disable stack loading items on HP38G, HP39/40G
BOOL bStackEnable = cCurrentRomType!='6' && cCurrentRomType!='A' && cCurrentRomType!='E' && cCurrentRomType!='P'; // CdB for HP: add P type
switch (iType)
{
case XTYP_CONNECT:
// get service name
DdeQueryString(idDdeInst,hsz2,szBuffer,ARRAYSIZEOF(szBuffer),0);
if (0 != lstrcmp(szBuffer,szAppName))
return (HDDEDATA) FALSE;
// get topic name
DdeQueryString(idDdeInst,hsz1,szBuffer,ARRAYSIZEOF(szBuffer),0);
return (HDDEDATA) (INT_PTR) (0 == lstrcmp(szBuffer,szTopic));
case XTYP_POKE:
// quit on models without stack or illegal data format or not in running state
if (!bStackEnable || iFmt != uCF_HpObj || nState != SM_RUN)
return (HDDEDATA) DDE_FNOTPROCESSED;
// get item name
DdeQueryString(idDdeInst,hsz2,szBuffer,ARRAYSIZEOF(szBuffer),0);
nStkLvl = _tcstoul(szBuffer,&psz,10);
if (*psz != 0 || nStkLvl < 1) // invalid number format
return (HDDEDATA) DDE_FNOTPROCESSED;
SuspendDebugger(); // suspend debugger
bDbgAutoStateCtrl = FALSE; // disable automatic debugger state control
if (!(Chipset.IORam[BITOFFSET]&DON)) // HP off
{
// turn on HP
KeyboardEvent(TRUE,0,0x8000);
Sleep(dwWakeupDelay);
KeyboardEvent(FALSE,0,0x8000);
}
if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state
{
hReturn = DDE_FNOTPROCESSED;
goto cancel;
}
while (nState!=nNextState) Sleep(0);
_ASSERT(nState==SM_SLEEP);
bSuccess = FALSE;
// get data and size
lpData = DdeAccessData(hData,&dwSize);
// has object length header
if (lpData && dwSize >= sizeof(DWORD))
{
dwIndex = *(LPDWORD) lpData; // object length
if (dwIndex <= dwSize - sizeof(DWORD))
{
// reserve unpacked object length memory
LPBYTE pbyMem = (LPBYTE) malloc(dwIndex * 2);
if (pbyMem != NULL)
{
// copy data and write to stack
CopyMemory(pbyMem+dwIndex,lpData+sizeof(DWORD),dwIndex);
bSuccess = (WriteStack(nStkLvl,pbyMem,dwIndex) == S_ERR_NO);
free(pbyMem); // free memory
}
}
}
DdeUnaccessData(hData);
SwitchToState(SM_RUN); // run state
while (nState!=nNextState) Sleep(0);
_ASSERT(nState==SM_RUN);
if (bSuccess == FALSE)
{
hReturn = DDE_FNOTPROCESSED;
goto cancel;
}
KeyboardEvent(TRUE,0,0x8000);
Sleep(dwWakeupDelay);
KeyboardEvent(FALSE,0,0x8000);
// wait for sleep mode
while (Chipset.Shutdn == FALSE) Sleep(0);
hReturn = (HDDEDATA) DDE_FACK;
cancel:
bDbgAutoStateCtrl = TRUE; // enable automatic debugger state control
ResumeDebugger();
return hReturn;
case XTYP_REQUEST:
// quit on models without stack or illegal data format or not in running state
if (!bStackEnable || iFmt != uCF_HpObj || nState != SM_RUN)
return NULL;
// get item name
DdeQueryString(idDdeInst,hsz2,szBuffer,ARRAYSIZEOF(szBuffer),0);
nStkLvl = _tcstoul(szBuffer,&psz,10);
if (*psz != 0 || nStkLvl < 1) // invalid number format
return NULL;
if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state
return NULL;
while (nState!=nNextState) Sleep(0);
_ASSERT(nState==SM_SLEEP);
dwAddress = RPL_Pick(nStkLvl); // pick address of stack level "item" object
if (dwAddress == 0)
{
SwitchToState(SM_RUN); // run state
return NULL;
}
dwLoop = dwSize = (RPL_SkipOb(dwAddress) - dwAddress + 1) / 2;
lpHeader = (Chipset.type == 'X' || Chipset.type == 'Q' || Chipset.type == '2') ? (LPBYTE) BINARYHEADER49 : (LPBYTE) BINARYHEADER48;
// length of binary header
dwIndex = (DWORD) strlen((LPCSTR) lpHeader);
// size of objectsize + header + object
dwSize += dwIndex + sizeof(DWORD);
// reserve memory
if ((lpData = (LPBYTE) malloc(dwSize)) == NULL)
{
SwitchToState(SM_RUN); // run state
return NULL;
}
// save data length
*(DWORD *)lpData = dwLoop + dwIndex;
// copy header
memcpy(lpData + sizeof(DWORD),lpHeader,dwIndex);
// copy data
for (dwIndex += sizeof(DWORD);dwLoop--;++dwIndex,dwAddress += 2)
lpData[dwIndex] = Read2(dwAddress);
// write data
hReturn = DdeCreateDataHandle(idDdeInst,lpData,dwSize,0,hsz2,iFmt,0);
free(lpData);
SwitchToState(SM_RUN); // run state
while (nState!=nNextState) Sleep(0);
_ASSERT(nState==SM_RUN);
return hReturn;
}
return NULL;
UNREFERENCED_PARAMETER(hConv);
UNREFERENCED_PARAMETER(dwData1);
UNREFERENCED_PARAMETER(dwData2);
}

1104
app/src/main/cpp/DEBUGDLL.C Normal file

File diff suppressed because it is too large Load diff

3638
app/src/main/cpp/DEBUGGER.C Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,39 @@
/*
* debugger.h
*
* This file is part of Emu48
*
* Copyright (C) 1999 Christoph Gießelink
*
*/
// breakpoint type definitions
#define BP_EXEC 0x01 // code breakpoint
#define BP_READ 0x02 // read memory breakpoint
#define BP_WRITE 0x04 // write memory breakpoint
#define BP_RPL 0x08 // RPL breakpoint
#define BP_ACCESS (BP_READ|BP_WRITE) // read/write memory breakpoint
// breakpoint notify definitions
#define BN_ASM 0 // ASM breakpoint
#define BN_RPL 1 // RPL breakpoint
#define BN_ASM_BT 2 // ASM and RPL breakpoint
// debugger state definitions
#define DBG_SUSPEND -1
#define DBG_OFF 0
#define DBG_RUN 1
#define DBG_STEPINTO 2
#define DBG_STEPOVER 3
#define DBG_STEPOUT 4
// debugger.c
extern VOID UpdateDbgCycleCounter(VOID);
extern BOOL CheckBreakpoint(DWORD dwAddr, DWORD wRange, UINT nType);
extern VOID NotifyDebugger(INT nType);
extern VOID DisableDebugger(VOID);
extern LRESULT OnToolDebug(VOID);
extern VOID LoadBreakpointList(HANDLE hFile);
extern VOID SaveBreakpointList(HANDLE hFile);
extern VOID CreateBackupBreakpointList(VOID);
extern VOID RestoreBackupBreakpointList(VOID);

1845
app/src/main/cpp/DISASM.C Normal file

File diff suppressed because it is too large Load diff

245
app/src/main/cpp/DISMEM.C Normal file
View file

@ -0,0 +1,245 @@
/*
* dismem.c
*
* This file is part of Emu48
*
* Copyright (C) 2012 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
typedef struct // type of model memory mapping
{
BYTE byType; // calculator type
CONST LPBYTE *ppbyNCE1; // NCE1 data
CONST DWORD *pdwNCE1Size; // NCE1 size
CONST LPBYTE *ppbyNCE2; // NCE2 data
CONST DWORD *pdwNCE2Size; // NCE2 size
CONST LPBYTE *ppbyCE1; // CE1 data
CONST DWORD *pdwCE1Size; // CE1 size
CONST LPBYTE *ppbyCE2; // CE2 data
CONST DWORD *pdwCE2Size; // CE2 size
CONST LPBYTE *ppbyNCE3; // NCE3 data
CONST DWORD *pdwNCE3Size; // NCE3 size
} MODEL_MAP_T;
static CONST LPBYTE pbyNoMEM = NULL; // no memory module
static CONST MODEL_MAP_T MemMap[] =
{
{
0, // default
&pbyNoMEM, NULL, // nc.
&pbyNoMEM, NULL, // nc.
&pbyNoMEM, NULL, // nc.
&pbyNoMEM, NULL, // nc.
&pbyNoMEM, NULL // nc.
},
{
'6', // HP38G (64K)
&pbyRom, &dwRomSize, // ROM
&Port0, &Chipset.Port0Size, // RAM
&pbyNoMEM, NULL, // nc.
&pbyNoMEM, NULL, // nc.
&pbyNoMEM, NULL // nc.
},
{
'A', // HP38G
&pbyRom, &dwRomSize, // ROM
&Port0, &Chipset.Port0Size, // RAM
&pbyNoMEM, NULL, // nc.
&pbyNoMEM, NULL, // nc.
&pbyNoMEM, NULL // nc.
},
{
'E', // HP39/40G
&pbyRom, &dwRomSize, // ROM
&Port0, &Chipset.Port0Size, // RAM part 1
&pbyNoMEM, NULL, // BS
&pbyNoMEM, NULL, // nc.
&Port2, &Chipset.Port2Size // RAM part 2
},
{
'G', // HP48GX
&pbyRom, &dwRomSize, // ROM
&Port0, &Chipset.Port0Size, // RAM
&pbyNoMEM, NULL, // BS
&Port1, &Chipset.Port1Size, // Card slot 1
&pbyPort2, &dwPort2Size // Card slot 2
},
{
'S', // HP48SX
&pbyRom, &dwRomSize, // ROM
&Port0, &Chipset.Port0Size, // RAM
&Port1, &Chipset.Port1Size, // Card slot 1
&pbyPort2, &dwPort2Size, // Card slot 2
&pbyNoMEM, NULL // nc.
},
{
'X', // HP49G
&pbyRom, &dwRomSize, // Flash
&Port0, &Chipset.Port0Size, // RAM
&pbyNoMEM, NULL, // BS
&Port1, &Chipset.Port1Size, // Port 1 part 1
&Port2, &Chipset.Port2Size // Port 1 part 2
},
{ // CdB for HP: add Q type
'Q', // HP49g+
&pbyRom, &dwRomSize, // Flash
&Port0, &Chipset.Port0Size, // RAM
&pbyNoMEM, NULL, // BS
&Port1, &Chipset.Port1Size, // Port 1 part 1
&Port2, &Chipset.Port2Size // Port 1 part 2
},
{ // CdB for HP: add 2 type
'2', // HP48gII
&pbyRom, &dwRomSize, // ROM
&Port0, &Chipset.Port0Size, // RAM
&pbyNoMEM, NULL, // BS
&pbyNoMEM, NULL, // Port 1 part 1
&pbyNoMEM, NULL, // Port 1 part 2
},
{ // CdB for HP: add P type
'P', // HP39g+/gs
&pbyRom, &dwRomSize, // ROM
&Port0, &Chipset.Port0Size, // RAM
&pbyNoMEM, NULL, // BS
&pbyNoMEM, NULL, // nc.
&Port2, &Chipset.Port2Size // RAM part 2
}
};
static MODEL_MAP_T CONST *pMapping = MemMap; // model specific memory mapping
static enum MEM_MAPPING eMapType = MEM_MMU; // MMU memory mapping
static LPBYTE pbyMapData = NULL;
static DWORD dwMapDataSize = 0;
static DWORD dwMapDataMask = 0;
BOOL SetMemRomType(BYTE cCurrentRomType)
{
UINT i;
pMapping = MemMap; // init default mapping
// scan for all table entries
for (i = 0; i < ARRAYSIZEOF(MemMap); ++i)
{
if (MemMap[i].byType == cCurrentRomType)
{
pMapping = &MemMap[i]; // found entry
return TRUE;
}
}
return FALSE;
}
BOOL SetMemMapType(enum MEM_MAPPING eType)
{
BOOL bSucc = TRUE;
eMapType = eType;
switch (eMapType)
{
case MEM_MMU:
pbyMapData = NULL; // data
dwMapDataSize = 512 * 1024 * 2; // data size
dwMapDataMask = dwMapDataSize - 1; // size mask
break;
case MEM_NCE1:
pbyMapData = *pMapping->ppbyNCE1;
dwMapDataSize = *pMapping->pdwNCE1Size; // ROM size is always in nibbles
dwMapDataMask = dwMapDataSize - 1; // size mask
break;
case MEM_NCE2:
pbyMapData = *pMapping->ppbyNCE2;
dwMapDataSize = *pMapping->pdwNCE2Size * 1024 * 2;
dwMapDataMask = dwMapDataSize - 1; // size mask
break;
case MEM_CE1:
pbyMapData = *pMapping->ppbyCE1;
dwMapDataSize = *pMapping->pdwCE1Size * 1024 * 2;
dwMapDataMask = dwMapDataSize - 1; // size mask
break;
case MEM_CE2:
pbyMapData = *pMapping->ppbyCE2;
dwMapDataSize = *pMapping->pdwCE2Size * 1024 * 2;
dwMapDataMask = dwMapDataSize - 1; // size mask
break;
case MEM_NCE3:
pbyMapData = *pMapping->ppbyNCE3;
dwMapDataSize = *pMapping->pdwNCE3Size * 1024 * 2;
dwMapDataMask = dwMapDataSize - 1; // size mask
break;
default: _ASSERT(FALSE);
pbyMapData = NULL;
dwMapDataSize = 0;
dwMapDataMask = 0;
bSucc = FALSE;
}
return bSucc;
}
enum MEM_MAPPING GetMemMapType(VOID)
{
return eMapType;
}
BOOL GetMemAvail(enum MEM_MAPPING eType)
{
switch (eType)
{
case MEM_MMU: return TRUE;
case MEM_NCE1: return *pMapping->ppbyNCE1 != NULL;
case MEM_NCE2: return *pMapping->ppbyNCE2 != NULL;
case MEM_CE1: return *pMapping->ppbyCE1 != NULL;
case MEM_CE2: return *pMapping->ppbyCE2 != NULL;
case MEM_NCE3: return *pMapping->ppbyNCE3 != NULL;
default: _ASSERT(FALSE);
}
return FALSE;
}
DWORD GetMemDataSize(VOID)
{
return dwMapDataSize;
}
DWORD GetMemDataMask(VOID)
{
return dwMapDataMask;
}
BYTE GetMemNib(DWORD *p)
{
BYTE byVal;
if (pbyMapData == NULL)
{
Npeek(&byVal, *p, 1);
}
else
{
byVal = pbyMapData[*p];
}
*p = (*p + 1) & dwMapDataMask;
return byVal;
}
VOID GetMemPeek(BYTE *a, DWORD d, UINT s)
{
if (pbyMapData == NULL)
{
Npeek(a, d, s);
}
else
{
for (; s > 0; --s, ++d)
{
*a++ = pbyMapData[d & dwMapDataMask];
}
}
return;
}

746
app/src/main/cpp/DISPLAY.C Normal file
View file

@ -0,0 +1,746 @@
/*
* display.c
*
* This file is part of Emu48
*
* Copyright (C) 1995 Sebastien Carlier
* Copyright (C) 2002 Christoph Gießelink
*
*/
#include "pch.h"
#include "resource.h"
#include "Emu48.h"
#include "io.h"
#include "kml.h"
// #define DEBUG_DISPLAY // switch for DISPLAY debug purpose
#define NOCOLORSGRAY 8 // no. of colors in gray scale mode
#define NOCOLORSBW 2 // no. of colors in black and white mode
#define DISPLAY_FREQ 19 // display update 1/frequency (1/64) in ms (gray scale mode)
#define B 0x00000000 // black
#define W 0x00FFFFFF // white
#define I 0xFFFFFFFF // ignore
#define LCD_ROW (36*4) // max. pixel per line
#define GRAYMASK(c) (((((c)-1)>>1)<<24) \
|((((c)-1)>>1)<<16) \
|((((c)-1)>>1)<<8) \
|((((c)-1)>>1)))
#define DIBPIXEL4(d,p) *((DWORD*)(d)) = ((*((DWORD*)(d)) & dwGrayMask) << 1) | (p); \
*((LPBYTE*) &(d)) += 4
BOOL bGrayscale = FALSE;
UINT nBackgroundX = 0;
UINT nBackgroundY = 0;
UINT nBackgroundW = 0;
UINT nBackgroundH = 0;
UINT nLcdX = 0;
UINT nLcdY = 0;
UINT nLcdZoom = 1; // memory DC zoom
UINT nGdiXZoom = 1; // GDI x zoom
UINT nGdiYZoom = 1; // GDI y zoom
HDC hLcdDC = NULL;
HDC hMainDC = NULL;
HDC hAnnunDC = NULL; // annunciator DC
BYTE (*GetLineCounter)(VOID) = NULL;
VOID (*StartDisplay)(BYTE byInitial) = NULL;
VOID (*StopDisplay)(VOID) = NULL;
static BYTE GetLineCounterGray(VOID);
static BYTE GetLineCounterBW(VOID);
static VOID StartDisplayGray(BYTE byInitial);
static VOID StartDisplayBW(BYTE byInitial);
static VOID StopDisplayGray(VOID);
static VOID StopDisplayBW(VOID);
static LPBYTE pbyLcd;
static HBITMAP hLcdBitmap;
static HBITMAP hMainBitmap;
static HBITMAP hAnnunBitmap;
static DWORD Pattern[16];
static BYTE Buf[36];
static DWORD dwGrayMask;
static LARGE_INTEGER lLcdRef; // reference time for VBL counter
static UINT uLcdTimerId = 0;
static BYTE byVblRef = 0; // VBL stop reference
static DWORD dwKMLColor[64] = // color table loaded by KML script
{
W,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B,
B,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B,
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I
};
static struct
{
BITMAPINFOHEADER Lcd_bmih;
RGBQUAD bmiColors[NOCOLORSGRAY];
} bmiLcd =
{
{0x28,0/*x*/,0/*y*/,1,8,BI_RGB,0,0,0,NOCOLORSGRAY,0}
};
static __inline VOID BuildPattern(VOID)
{
WORD i,j;
for (i=0; i<16; ++i)
{
Pattern[i] = 0;
for (j=8; j>0; j>>=1)
{
Pattern[i] = (Pattern[i] << 8) | ((i&j) != 0);
}
}
return;
}
VOID UpdateContrast(BYTE byContrast)
{
RGBQUAD c,b;
INT i,nColors;
// table for max. 8 colors
const INT nCAdj[] = { 0, 1, 1, 2, 1, 2, 2, 3 };
// when display is off use contrast 0
if ((Chipset.IORam[BITOFFSET] & DON) == 0) byContrast = 0;
c = *(RGBQUAD*)&dwKMLColor[byContrast]; // pixel on color
b = *(RGBQUAD*)&dwKMLColor[byContrast+32]; // pixel off color
// if background color is undefined, use color 0 for compatibility
if (I == *(DWORD*)&b) b = *(RGBQUAD*)&dwKMLColor[0];
nColors = bGrayscale ? (NOCOLORSGRAY-1) : (NOCOLORSBW-1);
_ASSERT(nColors <= ARRAYSIZEOF(nCAdj)); // no. of colors must be smaller than entries in the gray color table
// fill color palette of bitmap
for (i = 0; i <= nColors; ++i)
{
bmiLcd.bmiColors[i] = b;
bmiLcd.bmiColors[i].rgbRed += ((INT) c.rgbRed - (INT) b.rgbRed) * nCAdj[i] / nCAdj[nColors];
bmiLcd.bmiColors[i].rgbGreen += ((INT) c.rgbGreen - (INT) b.rgbGreen) * nCAdj[i] / nCAdj[nColors];
bmiLcd.bmiColors[i].rgbBlue += ((INT) c.rgbBlue - (INT) b.rgbBlue) * nCAdj[i] / nCAdj[nColors];
}
// update palette information
_ASSERT(hLcdDC);
SetDIBColorTable(hLcdDC,0,ARRAYSIZEOF(bmiLcd.bmiColors),bmiLcd.bmiColors);
return;
}
VOID SetLcdColor(UINT nId, UINT nRed, UINT nGreen, UINT nBlue)
{
dwKMLColor[nId&0x3F] = ((nRed&0xFF)<<16)|((nGreen&0xFF)<<8)|(nBlue&0xFF);
return;
}
VOID SetLcdMode(BOOL bMode)
{
if ((bGrayscale = bMode))
{
// set pixel update mask
dwGrayMask = GRAYMASK(NOCOLORSGRAY);
GetLineCounter = GetLineCounterGray;
StartDisplay = StartDisplayGray;
StopDisplay = StopDisplayGray;
}
else
{
// set pixel update mask
dwGrayMask = GRAYMASK(NOCOLORSBW);
GetLineCounter = GetLineCounterBW;
StartDisplay = StartDisplayBW;
StopDisplay = StopDisplayBW;
}
UpdateContrast(Chipset.contrast);
return;
}
VOID CreateLcdBitmap(VOID)
{
// create LCD bitmap
bmiLcd.Lcd_bmih.biWidth = LCD_ROW;
bmiLcd.Lcd_bmih.biHeight = -SCREENHEIGHT; // CdB for HP: add 64/80 line display for apples
_ASSERT(hLcdDC == NULL);
VERIFY(hLcdDC = CreateCompatibleDC(hWindowDC));
VERIFY(hLcdBitmap = CreateDIBSection(hWindowDC,(BITMAPINFO*)&bmiLcd,DIB_RGB_COLORS,(VOID **)&pbyLcd,NULL,0));
hLcdBitmap = (HBITMAP) SelectObject(hLcdDC,hLcdBitmap);
_ASSERT(hPalette != NULL);
SelectPalette(hLcdDC,hPalette,FALSE); // set palette for LCD DC
RealizePalette(hLcdDC); // realize palette
BuildPattern(); // build Nibble -> DIB mask pattern
SetLcdMode(bGrayscale); // init display update function pointer
return;
}
VOID DestroyLcdBitmap(VOID)
{
// set contrast palette to startup colors
WORD i = 0; dwKMLColor[i++] = W;
while (i < 32) dwKMLColor[i++] = B;
while (i < 64) dwKMLColor[i++] = I;
GetLineCounter = NULL;
StartDisplay = NULL;
StopDisplay = NULL;
if (hLcdDC != NULL)
{
// destroy LCD bitmap
DeleteObject(SelectObject(hLcdDC,hLcdBitmap));
DeleteDC(hLcdDC);
hLcdDC = NULL;
hLcdBitmap = NULL;
}
return;
}
BOOL CreateMainBitmap(LPCTSTR szFilename)
{
_ASSERT(hWindowDC != NULL);
VERIFY(hMainDC = CreateCompatibleDC(hWindowDC));
if (hMainDC == NULL) return FALSE; // quit if failed
hMainBitmap = LoadBitmapFile(szFilename);
if (hMainBitmap == NULL)
{
DeleteDC(hMainDC);
hMainDC = NULL;
return FALSE;
}
hMainBitmap = (HBITMAP) SelectObject(hMainDC,hMainBitmap);
_ASSERT(hPalette != NULL);
VERIFY(SelectPalette(hMainDC,hPalette,FALSE));
RealizePalette(hMainDC);
return TRUE;
}
VOID DestroyMainBitmap(VOID)
{
if (hMainDC != NULL)
{
// destroy Main bitmap
DeleteObject(SelectObject(hMainDC,hMainBitmap));
DeleteDC(hMainDC);
hMainDC = NULL;
hMainBitmap = NULL;
}
return;
}
//
// load annunciator bitmap
//
BOOL CreateAnnunBitmap(LPCTSTR szFilename)
{
_ASSERT(hWindowDC != NULL);
VERIFY(hAnnunDC = CreateCompatibleDC(hWindowDC));
if (hAnnunDC == NULL) return FALSE; // quit if failed
hAnnunBitmap = LoadBitmapFile(szFilename);
if (hAnnunBitmap == NULL)
{
DeleteDC(hAnnunDC);
hAnnunDC = NULL;
return FALSE;
}
hAnnunBitmap = (HBITMAP) SelectObject(hAnnunDC,hAnnunBitmap);
return TRUE;
}
//
// destroy annunciator bitmap
//
VOID DestroyAnnunBitmap(VOID)
{
if (hAnnunDC != NULL)
{
VERIFY(DeleteObject(SelectObject(hAnnunDC,hAnnunBitmap)));
DeleteDC(hAnnunDC);
hAnnunDC = NULL;
hAnnunBitmap = NULL;
}
return;
}
//****************
//*
//* LCD functions
//*
//****************
VOID UpdateDisplayPointers(VOID)
{
EnterCriticalSection(&csLcdLock);
{
#if defined DEBUG_DISPLAY
{
TCHAR buffer[256];
wsprintf(buffer,_T("%.5lx: Update Display Pointer\n"),Chipset.pc);
OutputDebugString(buffer);
}
#endif
// calculate display width
Chipset.width = (34 + Chipset.loffset + (Chipset.boffset / 4) * 2) & 0xFFFFFFFE;
Chipset.end1 = Chipset.start1 + MAINSCREENHEIGHT * Chipset.width;
if (Chipset.end1 < Chipset.start1)
{
// calculate first address of main display
Chipset.start12 = Chipset.end1 - Chipset.width;
// calculate last address of main display
Chipset.end1 = Chipset.start1 - Chipset.width;
}
else
{
Chipset.start12 = Chipset.start1;
}
Chipset.end2 = Chipset.start2 + MENUHEIGHT * 34;
}
LeaveCriticalSection(&csLcdLock);
return;
}
VOID UpdateMainDisplay(VOID)
{
UINT x, y;
BYTE *p = pbyLcd+(Chipset.d0size*LCD_ROW); // CdB for HP: add 64/80 line display for apples
DWORD d = Chipset.start1;
#if defined DEBUG_DISPLAY
{
TCHAR buffer[256];
wsprintf(buffer,_T("%.5lx: Update Main Display\n"),Chipset.pc);
OutputDebugString(buffer);
}
#endif
if (!(Chipset.IORam[BITOFFSET]&DON))
{
ZeroMemory(pbyLcd, LCD_ROW * SCREENHEIGHT);
}
else
{
for (y = 0; y < MAINSCREENHEIGHT; ++y)
{
Npeek(Buf,d,36);
for (x=0; x<36; ++x) // every 4 pixel
{
DIBPIXEL4(p,Pattern[Buf[x]]);
// check for display buffer overflow
_ASSERT(p <= pbyLcd + LCD_ROW * SCREENHEIGHT);
}
d+=Chipset.width;
}
}
EnterCriticalSection(&csGDILock); // solving NT GDI problems
{
// CdB for HP: add 64/80 line display for apples
StretchBlt(hWindowDC, nLcdX, nLcdY+Chipset.d0size*nLcdZoom, 131*nLcdZoom*nGdiXZoom, MAINSCREENHEIGHT*nLcdZoom*nGdiYZoom,
hLcdDC, Chipset.boffset, Chipset.d0size, 131, MAINSCREENHEIGHT, SRCCOPY);
GdiFlush();
}
LeaveCriticalSection(&csGDILock);
return;
}
VOID UpdateMenuDisplay(VOID)
{
UINT x, y;
BYTE *p;
DWORD d = Chipset.start2;
#if defined DEBUG_DISPLAY
{
TCHAR buffer[256];
wsprintf(buffer,_T("%.5lx: Update Menu Display\n"),Chipset.pc);
OutputDebugString(buffer);
}
#endif
if (!(Chipset.IORam[BITOFFSET]&DON)) return;
if (MENUHEIGHT==0) return; // menu disabled
// calculate bitmap offset
p = pbyLcd + ((Chipset.d0size+MAINSCREENHEIGHT)*LCD_ROW); // CdB for HP: add 64/80 line display for apples
for (y = 0; y < MENUHEIGHT; ++y)
{
Npeek(Buf,d,34); // 34 nibbles are viewed
for (x=0; x<34; ++x) // every 4 pixel
{
DIBPIXEL4(p,Pattern[Buf[x]]);
// check for display buffer overflow
_ASSERT(p <= pbyLcd + LCD_ROW * SCREENHEIGHT);
}
// adjust pointer to 36 DIBPIXEL drawing calls
p += (36-34) * sizeof(DWORD);
d+=34;
}
EnterCriticalSection(&csGDILock); // solving NT GDI problems
{
// CdB for HP: add 64/80 line display for apples
StretchBlt(hWindowDC,
nLcdX, nLcdY+(MAINSCREENHEIGHT+Chipset.d0size)*nLcdZoom*nGdiYZoom,
131*nLcdZoom*nGdiXZoom, MENUHEIGHT*nLcdZoom*nGdiYZoom,
hLcdDC,
0, (MAINSCREENHEIGHT+Chipset.d0size),
131, MENUHEIGHT,
SRCCOPY);
GdiFlush();
}
LeaveCriticalSection(&csGDILock);
return;
}
// CdB for HP: add header management
VOID RefreshDisp0()
{
UINT x, y;
BYTE *p;
BYTE* d = Chipset.d0memory;
#if defined DEBUG_DISPLAY
{
TCHAR buffer[256];
wsprintf(buffer,_T("%.5lx: Update header Display\n"),Chipset.pc);
OutputDebugString(buffer);
}
#endif
if (!(Chipset.IORam[BITOFFSET]&DON)) return;
// calculate bitmap offset
p = pbyLcd;
for (y = 0; y<Chipset.d0size; ++y)
{
memcpy(Buf,d,34); // 34 nibbles are viewed
for (x=0; x<36; ++x) // every 4 pixel
{
DIBPIXEL4(p,Pattern[Buf[x]]);
}
d+=34;
}
EnterCriticalSection(&csGDILock); // solving NT GDI problems
{
StretchBlt(hWindowDC, nLcdX, nLcdY,
131*nLcdZoom*nGdiXZoom, Chipset.d0size*nLcdZoom*nGdiYZoom,
hLcdDC, Chipset.d0offset, 0, 131, Chipset.d0size, SRCCOPY);
GdiFlush();
}
LeaveCriticalSection(&csGDILock);
return;
}
VOID WriteToMainDisplay(LPBYTE a, DWORD d, UINT s)
{
UINT x0, x;
UINT y0, y;
DWORD *p;
INT lWidth = abs(Chipset.width); // display width
if (bGrayscale) return; // no direct writing in grayscale mode
#if defined DEBUG_DISPLAY
{
TCHAR buffer[256];
wsprintf(buffer,_T("%.5lx: Write Main Display %x,%u\n"),Chipset.pc,d,s);
OutputDebugString(buffer);
}
#endif
if (!(Chipset.IORam[BITOFFSET]&DON)) // display off
return; // no drawing
if (MAINSCREENHEIGHT == 0) return; // menu disabled
d -= Chipset.start1; // nibble offset to DISPADDR (start of display)
y0 = y = (d / lWidth) + Chipset.d0size; // bitmap row
x0 = x = d % lWidth; // bitmap coloumn
p = (DWORD*)(pbyLcd + y0*LCD_ROW + x0*sizeof(*p));
// outside main display area
// _ASSERT(y0 >= (INT)Chipset.d0size && y0 < (INT)(MAINSCREENHEIGHT+Chipset.d0size));
if (!(y0 >= (INT)Chipset.d0size && y0 < (INT)(MAINSCREENHEIGHT+Chipset.d0size))) return;
while (s--) // loop for nibbles to write
{
if (x<36) // only fill visible area
{
*p = Pattern[*a];
}
++a; // next value to write
++x; // next x position
if (((INT) x==lWidth)&&s) // end of display line
{
x = 0; // first coloumn
++y; // next row
if (y == (INT) MAINSCREENHEIGHT+Chipset.d0size) break;
// recalculate bitmap memory position of new line
p = (DWORD*) (pbyLcd+y*LCD_ROW); // CdB for HP: add 64/80 line display for apples
}
else
p++;
}
if (y==y0) y++;
EnterCriticalSection(&csGDILock); // solving NT GDI problems
{
StretchBlt(hWindowDC, nLcdX, nLcdY+y0*nLcdZoom*nGdiYZoom,
131*nLcdZoom*nGdiXZoom, (y-y0)*nLcdZoom*nGdiYZoom,
hLcdDC, Chipset.boffset, y0, 131, y-y0, SRCCOPY); // CdB for HP: add 64/80 line display for apples
GdiFlush();
}
LeaveCriticalSection(&csGDILock);
return;
}
VOID WriteToMenuDisplay(LPBYTE a, DWORD d, UINT s)
{
UINT x0, x;
UINT y0, y;
DWORD *p;
if (bGrayscale) return; // no direct writing in grayscale mode
#if defined DEBUG_DISPLAY
{
TCHAR buffer[256];
wsprintf(buffer,_T("%.5lx: Write Menu Display %x,%u\n"),Chipset.pc,d,s);
OutputDebugString(buffer);
}
#endif
if (!(Chipset.IORam[BITOFFSET]&DON)) return;
if (MENUHEIGHT == 0) return; // menu disabled
d -= Chipset.start2;
y0 = y = (d / 34) + MAINSCREENHEIGHT+Chipset.d0size; // bitmap row
x0 = x = d % 34;
p = (DWORD*)(pbyLcd + y0*LCD_ROW + x0*sizeof(*p));
// outside menu display area
// _ASSERT(y0 >= (INT)(Chipset.d0size+MAINSCREENHEIGHT) && y0 < (INT)(SCREENHEIGHT));
if (!(y0 >= (UINT)(Chipset.d0size+MAINSCREENHEIGHT) && y0 < (UINT)(SCREENHEIGHT))) return;
while (s--) // loop for nibbles to write
{
if (x<36) // only fill visible area
{
*p = Pattern[*a];
}
a++; // next value to write
x++; // next x position
if ((x==34)&&s) // end of display line
{
x = 0; // first coloumn
y++; // next row
if (y == SCREENHEIGHTREAL) break;
// recalculate bitmap memory position of new line
p=(DWORD*)(pbyLcd+y*LCD_ROW); // CdB for HP: add 64/80 ligne display for apples
} else p++;
}
if (y==y0) y++;
EnterCriticalSection(&csGDILock); // solving NT GDI problems
{
StretchBlt(hWindowDC, nLcdX, nLcdY+y0*nLcdZoom*nGdiYZoom,
(131*nLcdZoom)*nGdiXZoom, (y-y0)*nLcdZoom*nGdiYZoom,
hLcdDC, 0, y0, 131, y-y0, SRCCOPY); // CdB for HP: add 64/80 line display for apples
GdiFlush();
}
LeaveCriticalSection(&csGDILock);
return;
}
VOID UpdateAnnunciators(VOID)
{
BYTE c;
c = (BYTE)(Chipset.IORam[ANNCTRL] | (Chipset.IORam[ANNCTRL+1]<<4));
// switch annunciators off if timer stopped
if ((c & AON) == 0 || (Chipset.IORam[TIMER2_CTRL] & RUN) == 0)
c = 0;
DrawAnnunciator(1,c&LA1);
DrawAnnunciator(2,c&LA2);
DrawAnnunciator(3,c&LA3);
DrawAnnunciator(4,c&LA4);
DrawAnnunciator(5,c&LA5);
DrawAnnunciator(6,c&LA6);
return;
}
VOID ResizeWindow(VOID)
{
if (hWnd != NULL) // if window created
{
RECT rectWindow;
RECT rectClient;
rectWindow.left = 0;
rectWindow.top = 0;
rectWindow.right = nBackgroundW;
rectWindow.bottom = nBackgroundH;
AdjustWindowRect(&rectWindow,
(DWORD) GetWindowLongPtr(hWnd,GWL_STYLE),
GetMenu(hWnd) != NULL || IsRectEmpty(&rectWindow));
SetWindowPos(hWnd, bAlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0,
rectWindow.right - rectWindow.left,
rectWindow.bottom - rectWindow.top,
SWP_NOMOVE);
// check if menu bar wrapped to two or more rows
GetClientRect(hWnd, &rectClient);
if (rectClient.bottom < (LONG) nBackgroundH)
{
rectWindow.bottom += (nBackgroundH - rectClient.bottom);
SetWindowPos (hWnd, NULL, 0, 0,
rectWindow.right - rectWindow.left,
rectWindow.bottom - rectWindow.top,
SWP_NOMOVE | SWP_NOZORDER);
}
EnterCriticalSection(&csGDILock); // solving NT GDI problems
{
_ASSERT(hWindowDC); // move origin of destination window
VERIFY(SetWindowOrgEx(hWindowDC, nBackgroundX, nBackgroundY, NULL));
GdiFlush();
}
LeaveCriticalSection(&csGDILock);
InvalidateRect(hWnd,NULL,TRUE);
}
return;
}
//################
//#
//# functions for gray scale implementation
//#
//################
// main display update routine
static VOID CALLBACK LcdProc(UINT uEventId, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
EnterCriticalSection(&csLcdLock);
{
UpdateMainDisplay(); // update display
UpdateMenuDisplay();
RefreshDisp0(); // CdB for HP: add header management
}
LeaveCriticalSection(&csLcdLock);
QueryPerformanceCounter(&lLcdRef); // actual time
return;
UNREFERENCED_PARAMETER(uEventId);
UNREFERENCED_PARAMETER(uMsg);
UNREFERENCED_PARAMETER(dwUser);
UNREFERENCED_PARAMETER(dw1);
UNREFERENCED_PARAMETER(dw2);
}
// LCD line counter calculation
static BYTE GetLineCounterGray(VOID)
{
LARGE_INTEGER lLC;
BYTE byTime;
if (uLcdTimerId == 0) // display off
return ((Chipset.IORam[LINECOUNT+1] & (LC5|LC4)) << 4) | Chipset.IORam[LINECOUNT];
QueryPerformanceCounter(&lLC); // get elapsed time since display update
// elapsed ticks so far
byTime = (BYTE) (((lLC.QuadPart - lLcdRef.QuadPart) << 12) / lFreq.QuadPart);
if (byTime > 0x3F) byTime = 0x3F; // all counts made
return 0x3F - byTime; // update display between VBL counter 0x3F-0x3E
}
static VOID StartDisplayGray(BYTE byInitial)
{
if (uLcdTimerId) // LCD update timer running
return; // -> quit
if (Chipset.IORam[BITOFFSET]&DON) // display on?
{
QueryPerformanceCounter(&lLcdRef); // actual time of top line
// adjust startup counter to get the right VBL value
_ASSERT(byInitial <= 0x3F); // line counter value 0 - 63
lLcdRef.QuadPart -= ((LONGLONG) (0x3F - byInitial) * lFreq.QuadPart) >> 12;
VERIFY(uLcdTimerId = timeSetEvent(DISPLAY_FREQ,0,(LPTIMECALLBACK)&LcdProc,0,TIME_PERIODIC));
}
return;
}
static VOID StopDisplayGray(VOID)
{
BYTE a[2];
ReadIO(a,LINECOUNT,2,TRUE); // update VBL at display off time
if (uLcdTimerId == 0) // timer stopped
return; // -> quit
timeKillEvent(uLcdTimerId); // stop display update
uLcdTimerId = 0; // set flag display update stopped
EnterCriticalSection(&csLcdLock); // update to last condition
{
UpdateMainDisplay(); // update display
UpdateMenuDisplay();
RefreshDisp0(); // CdB for HP: add header management
}
LeaveCriticalSection(&csLcdLock);
return;
}
//################
//#
//# functions for black and white implementation
//#
//################
// LCD line counter calculation in BW mode
static BYTE F4096Hz(VOID) // get a 6 bit 4096Hz down counter value
{
LARGE_INTEGER lLC;
QueryPerformanceCounter(&lLC); // get counter value
// calculate 4096 Hz frequency down counter value
return -(BYTE)(((lLC.QuadPart - lAppStart.QuadPart) << 12) / lFreq.QuadPart) & 0x3F;
}
static BYTE GetLineCounterBW(VOID) // get line counter value
{
_ASSERT(byVblRef < 0x40);
return (0x40 + F4096Hz() - byVblRef) & 0x3F;
}
static VOID StartDisplayBW(BYTE byInitial)
{
// get positive VBL difference between now and stop time
byVblRef = (0x40 + F4096Hz() - byInitial) & 0x3F;
return;
}
static VOID StopDisplayBW(VOID)
{
BYTE a[2];
ReadIO(a,LINECOUNT,2,TRUE); // update VBL at display off time
return;
}

1592
app/src/main/cpp/DISRPL.C Normal file

File diff suppressed because it is too large Load diff

25
app/src/main/cpp/DISRPL.H Normal file
View file

@ -0,0 +1,25 @@
/*
* disrpl.h
*
* This file is part of Emu48
*
* Copyright (C) 2008 Christoph Gießelink
*
*/
// RPL platform type
#define RPL_P1 (1<<0) // Clamshell without RRP
#define RPL_P2 (RPL_P1 | (1<<1)) // Pioneer / Clamshell
#define RPL_P3 (RPL_P2 | (1<<2)) // Charlemagne
#define RPL_P4 (RPL_P3 | (1<<3)) // Alcuin
#define RPL_P5 (RPL_P4 | (1<<4)) // V'ger
extern DWORD dwRplPlatform; // RPL platform
extern BOOL bRplViewName; // show entry point name
extern BOOL bRplViewAddr; // show adress
extern BOOL bRplViewBin; // show binary data
extern BOOL bRplViewAsm; // show ASM code instead of hex data
extern BYTE (*RplReadNibble)(DWORD *p); // read nibble function pointer
extern DWORD RplSkipObject(DWORD dwAddr);
extern LPTSTR RplDecodeObject(DWORD dwAddr, DWORD *pdwNxtAddr);
extern LPTSTR RplCreateObjView(DWORD dwStartAddr, DWORD dwEndAddr, BOOL bSingleObj);

2288
app/src/main/cpp/EMU48.C Normal file

File diff suppressed because it is too large Load diff

459
app/src/main/cpp/EMU48.H Normal file
View file

@ -0,0 +1,459 @@
/*
* Emu48.h
*
* This file is part of Emu48
*
* Copyright (C) 1995 Sebastien Carlier
*
*/
#include "types.h"
#define HARDWARE "Yorke" // emulator hardware
#define MODELS "26AEGPQSX" // valid calculator models
#define APPLEHARD "2PQ" // Apple platform calculator models
#define ARRAYSIZEOF(a) (sizeof(a) / sizeof(a[0]))
// cards status
#define PORT1_PRESENT ((cCurrentRomType=='S')?P1C:P2C)
#define PORT1_WRITE ((cCurrentRomType=='S')?P1W:P2W)
#define PORT2_PRESENT ((cCurrentRomType=='S')?P2C:P1C)
#define PORT2_WRITE ((cCurrentRomType=='S')?P2W:P1W)
#define BINARYHEADER48 "HPHP48-W"
#define BINARYHEADER49 "HPHP49-W"
#define BIN_FILTER "Port Data File (*.BIN)\0*.BIN\0All Files (*.*)\0*.*\0"
#define HP_FILTER "HP Binary Object (*.HP;*.LIB)\0*.HP;*.LIB\0All Files (*.*)\0*.*\0"
#define CF_HPOBJ "CF_HPOBJ" // clipboard format for DDE
// CPU cycles in 16384 Hz time frame
#define T2CYCLES ((cCurrentRomType=='S')?dwSXCycles:(cCurrentRomType=='G')?dwGXCycles:(cCurrentRomType=='P')?dwGPCycles:(cCurrentRomType=='Q')?dwGPCycles:dwG2Cycles) // CdB for HP: add apples
#define SM_RUN 0 // states of cpu emulation thread
#define SM_INVALID 1
#define SM_RETURN 2
#define SM_SLEEP 3
#define S_ERR_NO 0 // stack errorcodes
#define S_ERR_OBJECT 1
#define S_ERR_BINARY 2
#define S_ERR_ASCII 3
#define BAD_OB (0xFFFFFFFF) // bad object
#define NO_SERIAL "disabled" // port not open
#define HP_MNEMONICS FALSE // disassembler mnenomics mode
#define CLASS_MNEMONICS TRUE
#define MACRO_OFF 0 // macro recorder off
#define MACRO_NEW 1
#define MACRO_PLAY 2
#define DISP_POINTER 0x01 // defines for display area
#define DISP_MAIN 0x02
#define DISP_MENUE 0x04
#define DISP_ANNUN 0x08
#define ROMPAGESIZE (1<<12) // ROM dirty page size in nibbles
// window styles
#define STYLE_TITLE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_OVERLAPPED)
#define STYLE_NOTITLE (WS_POPUP|WS_SYSMENU|WS_MINIMIZEBOX|WS_CLIPSIBLINGS)
// WM_COPYDATA identifier
#define CDID_FILENAME 1 // send file name
// macro to check for valid calculator model
#define isModelValid(m) (m != 0 && strchr(MODELS,m) != NULL)
#define isModelApple(m) (m != 0 && strchr(APPLEHARD,m) != NULL)
// values for mapping area
enum MMUMAP { M_IO, M_ROM, M_RAM, M_P1, M_P2, M_BS };
// values for disassembler memory mapping modes
enum MEM_MAPPING { MEM_MMU, MEM_NCE1, MEM_NCE2, MEM_CE1, MEM_CE2, MEM_NCE3 };
// Emu48.c
extern HPALETTE hPalette;
extern HPALETTE hOldPalette;
extern HANDLE hEventShutdn;
extern LPTSTR szAppName;
extern LPTSTR szTopic;
extern LPTSTR szTitle;
extern CRITICAL_SECTION csGDILock;
extern CRITICAL_SECTION csLcdLock;
extern CRITICAL_SECTION csKeyLock;
extern CRITICAL_SECTION csIOLock;
extern CRITICAL_SECTION csT1Lock;
extern CRITICAL_SECTION csT2Lock;
extern CRITICAL_SECTION csTxdLock;
extern CRITICAL_SECTION csRecvLock;
extern CRITICAL_SECTION csSlowLock;
extern CRITICAL_SECTION csDbgLock;
extern INT nArgc;
extern LPCTSTR *ppArgv;
extern LARGE_INTEGER lFreq;
extern LARGE_INTEGER lAppStart;
extern DWORD idDdeInst;
extern UINT uCF_HpObj;
extern HINSTANCE hApp;
extern HWND hWnd;
extern HWND hDlgDebug;
extern HWND hDlgFind;
extern HWND hDlgProfile;
extern HWND hDlgRplObjView;
extern HDC hWindowDC;
extern DWORD dwTColor;
extern DWORD dwTColorTol;
extern HRGN hRgn;
extern HCURSOR hCursorArrow;
extern HCURSOR hCursorHand;
extern UINT uWaveDevId;
extern DWORD dwWakeupDelay;
extern BOOL bAutoSave;
extern BOOL bAutoSaveOnExit;
extern BOOL bSaveDefConfirm;
extern BOOL bStartupBackup;
extern BOOL bAlwaysDisplayLog;
extern BOOL bLoadObjectWarning;
extern BOOL bShowTitle;
extern BOOL bShowMenu;
extern BOOL bAlwaysOnTop;
extern BOOL bActFollowsMouse;
extern BOOL bClientWinMove;
extern BOOL bSingleInstance;
extern HANDLE hThread;
extern VOID SetWindowTitle(LPCTSTR szString);
extern VOID ForceForegroundWindow(HWND hWnd);
extern VOID CopyItemsToClipboard(HWND hWnd);
// mru.c
extern BOOL MruInit(UINT nNum);
extern VOID MruCleanup(VOID);
extern VOID MruAdd(LPCTSTR lpszEntry);
extern VOID MruRemove(UINT nIndex);
extern VOID MruMoveTop(UINT nIndex);
extern UINT MruEntries(VOID);
extern LPCTSTR MruFilename(UINT nIndex);
extern VOID MruUpdateMenu(HMENU hMenu);
extern VOID MruWriteList(VOID);
extern VOID MruReadList(VOID);
// Settings.c
extern VOID ReadSettings(VOID);
extern VOID WriteSettings(VOID);
extern VOID ReadLastDocument(LPTSTR szFileName, DWORD nSize);
extern VOID WriteLastDocument(LPCTSTR szFilename);
extern VOID ReadSettingsString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpDefault, LPTSTR lpData, DWORD dwSize);
extern VOID WriteSettingsString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPTSTR lpData);
extern INT ReadSettingsInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nDefault);
extern VOID WriteSettingsInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nValue);
extern VOID DelSettingsKey(LPCTSTR lpszSection, LPCTSTR lpszEntry);
// Display.c
extern BOOL bGrayscale;
extern UINT nBackgroundX;
extern UINT nBackgroundY;
extern UINT nBackgroundW;
extern UINT nBackgroundH;
extern UINT nLcdX;
extern UINT nLcdY;
extern UINT nLcdZoom;
extern UINT nGdiXZoom;
extern UINT nGdiYZoom;
extern HDC hLcdDC;
extern HDC hMainDC;
extern HDC hAnnunDC;
extern BYTE (*GetLineCounter)(VOID);
extern VOID (*StartDisplay)(BYTE byInitial);
extern VOID (*StopDisplay)(VOID);
extern VOID UpdateContrast(BYTE byContrast);
extern VOID SetLcdColor(UINT nId, UINT nRed, UINT nGreen, UINT nBlue);
extern VOID SetLcdMode(BOOL bMode);
extern VOID CreateLcdBitmap(VOID);
extern VOID DestroyLcdBitmap(VOID);
extern BOOL CreateMainBitmap(LPCTSTR szFilename);
extern VOID DestroyMainBitmap(VOID);
extern BOOL CreateAnnunBitmap(LPCTSTR szFilename);
extern VOID DestroyAnnunBitmap(VOID);
extern VOID UpdateDisplayPointers(VOID);
extern VOID UpdateMainDisplay(VOID);
extern VOID UpdateMenuDisplay(VOID);
extern VOID RefreshDisp0(); // CdB for HP: add apples display management
extern VOID WriteToMainDisplay(LPBYTE a, DWORD d, UINT s);
extern VOID WriteToMenuDisplay(LPBYTE a, DWORD d, UINT s);
extern VOID UpdateAnnunciators(VOID);
extern VOID ResizeWindow(VOID);
// Engine.c
extern BOOL bInterrupt;
extern UINT nState;
extern UINT nNextState;
extern BOOL bEnableSlow;
extern BOOL bRealSpeed;
extern BOOL bKeySlow;
extern BOOL bSoundSlow;
extern UINT nOpcSlow;
extern BOOL bCommInit;
extern CHIPSET Chipset;
extern TCHAR szSerialWire[16];
extern TCHAR szSerialIr[16];
extern DWORD dwSXCycles;
extern DWORD dwGXCycles;
extern DWORD dwGPCycles; // CdB for HP: add apples speed
extern DWORD dwG2Cycles; // CdB for HP: add apples speed
extern HANDLE hEventDebug;
extern BOOL bDbgAutoStateCtrl;
extern INT nDbgState;
extern BOOL bDbgNOP3;
extern BOOL bDbgCode;
extern BOOL bDbgRPL;
extern BOOL bDbgSkipInt;
extern DWORD dwDbgStopPC;
extern DWORD dwDbgRplPC;
extern DWORD dwDbgRstkp;
extern DWORD dwDbgRstk;
extern DWORD *pdwInstrArray;
extern WORD wInstrSize;
extern WORD wInstrWp;
extern WORD wInstrRp;
extern VOID SuspendDebugger(VOID);
extern VOID ResumeDebugger(VOID);
extern VOID CheckSerial(VOID);
extern VOID InitAdjustSpeed(VOID);
extern VOID AdjKeySpeed(VOID);
extern VOID SetSpeed(BOOL bAdjust);
extern VOID UpdateKdnBit(VOID);
extern BOOL WaitForSleepState(VOID);
extern UINT SwitchToState(UINT nNewState);
extern UINT WorkerThread(LPVOID pParam);
// Fetch.c
extern VOID EvalOpcode(LPBYTE I);
// Files.c
extern TCHAR szEmuDirectory[MAX_PATH];
extern TCHAR szRomDirectory[MAX_PATH];
extern TCHAR szCurrentDirectory[MAX_PATH];
extern TCHAR szCurrentKml[MAX_PATH];
extern TCHAR szBackupKml[MAX_PATH];
extern TCHAR szCurrentFilename[MAX_PATH];
extern TCHAR szBackupFilename[MAX_PATH];
extern TCHAR szBufferFilename[MAX_PATH];
extern TCHAR szPort2Filename[MAX_PATH];
extern BOOL bDocumentAvail;
extern BYTE cCurrentRomType;
extern UINT nCurrentClass;
extern LPBYTE Port0;
extern LPBYTE Port1;
extern LPBYTE Port2;
extern LPBYTE pbyRom;
extern BOOL bRomWriteable;
extern DWORD dwRomSize;
extern LPBYTE pbyRomDirtyPage;
extern DWORD dwRomDirtyPageSize;
extern WORD wRomCrc;
extern LPBYTE pbyPort2;
extern BOOL bPort2Writeable;
extern BOOL bPort2IsShared;
extern DWORD dwPort2Size;
extern DWORD dwPort2Mask;
extern WORD wPort2Crc;
extern BOOL bBackup;
extern VOID SetWindowLocation(HWND hWnd,INT nPosX,INT nPosY);
extern DWORD GetCutPathName(LPCTSTR szFileName,LPTSTR szBuffer,DWORD dwBufferLength,INT nCutLength);
extern VOID SetWindowPathTitle(LPCTSTR szFileName);
extern VOID UpdatePatches(BOOL bPatch);
extern BOOL PatchRom(LPCTSTR szFilename);
extern BOOL CrcRom(WORD *pwChk);
extern BOOL MapRom(LPCTSTR szFilename);
extern VOID UnmapRom(VOID);
extern BOOL CrcPort2(WORD *pwCrc);
extern BOOL MapPort2(LPCTSTR szFilename);
extern VOID UnmapPort2(VOID);
extern VOID ResetDocument(VOID);
extern BOOL NewDocument(VOID);
extern BOOL OpenDocument(LPCTSTR szFilename);
extern BOOL SaveDocument(VOID);
extern BOOL SaveDocumentAs(LPCTSTR szFilename);
extern BOOL SaveBackup(VOID);
extern BOOL RestoreBackup(VOID);
extern BOOL ResetBackup(VOID);
extern BOOL GetOpenFilename(VOID);
extern BOOL GetSaveAsFilename(VOID);
extern BOOL GetLoadObjectFilename(LPCTSTR lpstrFilter,LPCTSTR lpstrDefExt);
extern BOOL GetSaveObjectFilename(LPCTSTR lpstrFilter,LPCTSTR lpstrDefExt);
extern WORD WriteStack(UINT nStkLevel,LPBYTE lpBuf,DWORD dwSize);
extern BOOL LoadObject(LPCTSTR szFilename);
extern BOOL SaveObject(LPCTSTR szFilename);
extern BOOL LoadIconFromFile(LPCTSTR szFilename);
extern VOID LoadIconDefault(VOID);
extern HBITMAP LoadBitmapFile(LPCTSTR szFilename);
extern HRGN CreateRgnFromBitmap(HBITMAP hBmp,COLORREF color,DWORD dwTol);
// Timer.c
extern VOID SetHP48Time(VOID);
extern VOID StartTimers(VOID);
extern VOID StopTimers(VOID);
extern DWORD ReadT2(VOID);
extern VOID SetT2(DWORD dwValue);
extern BYTE ReadT1(VOID);
extern VOID SetT1(BYTE byValue);
// Mops.c
extern BOOL bFlashRomArray;
extern BYTE disp;
extern LPBYTE RMap[256];
extern LPBYTE WMap[256];
extern DWORD FlashROMAddr(DWORD d);
extern VOID Map(BYTE a, BYTE b);
extern VOID RomSwitch(DWORD adr);
extern VOID Config(VOID);
extern VOID Uncnfg(VOID);
extern VOID Reset(VOID);
extern VOID C_Eq_Id(VOID);
extern enum MMUMAP MapData(DWORD d);
extern VOID CpuReset(VOID);
extern VOID Npeek(BYTE *a, DWORD d, UINT s);
extern VOID Nread(BYTE *a, DWORD d, UINT s);
extern VOID Nwrite(BYTE *a, DWORD d, UINT s);
extern BYTE Read2(DWORD d);
extern DWORD Read5(DWORD d);
extern VOID Write5(DWORD d, DWORD n);
extern VOID Write2(DWORD d, BYTE n);
extern VOID IOBit(DWORD d, BYTE b, BOOL s);
extern VOID ReadIO(BYTE *a, DWORD b, DWORD s, BOOL bUpdate);
extern VOID WriteIO(BYTE *a, DWORD b, DWORD s);
// Lowbat.c
extern BOOL bLowBatDisable;
extern VOID StartBatMeasure(VOID);
extern VOID StopBatMeasure(VOID);
extern VOID GetBatteryState(BOOL *pbLBI, BOOL *pbVLBI);
// Keyboard.c
extern DWORD dwKeyMinDelay;
extern VOID ScanKeyboard(BOOL bActive, BOOL bReset);
extern VOID KeyboardEvent(BOOL bPress, UINT out, UINT in);
// Keymacro.c
extern INT nMacroState;
extern INT nMacroTimeout;
extern BOOL bMacroRealSpeed;
extern DWORD dwMacroMinDelay;
extern VOID KeyMacroRecord(BOOL bPress, UINT out, UINT in);
extern LRESULT OnToolMacroNew(VOID);
extern LRESULT OnToolMacroPlay(VOID);
extern LRESULT OnToolMacroStop(VOID);
extern LRESULT OnToolMacroSettings(VOID);
// Redeye.c
extern VOID IrPrinter(BYTE c);
// Udp.c
extern TCHAR szUdpServer[1024];
extern WORD wUdpPort;
extern VOID ResetUdp(VOID);
extern BOOL SendByteUdp(BYTE byData);
// Stack.c
extern BOOL bDetectClpObject;
extern LRESULT OnStackCopy(VOID);
extern LRESULT OnStackPaste(VOID);
// RPL.c
extern BOOL RPL_GetSystemFlag(INT nFlag);
extern DWORD RPL_SkipOb(DWORD d);
extern DWORD RPL_ObjectSize(BYTE *o,DWORD s);
extern DWORD RPL_CreateTemp(DWORD l,BOOL bGarbageCol);
extern UINT RPL_Depth(VOID);
extern DWORD RPL_Pick(UINT l);
extern VOID RPL_Replace(DWORD n);
extern VOID RPL_Push(UINT l,DWORD n);
// External.c
extern VOID External(CHIPSET* w);
extern VOID RCKBp(CHIPSET* w);
// SndEnum.c
extern VOID SetSoundDeviceList(HWND hWnd,UINT uDeviceID);
// Sound.c
extern DWORD dwWaveVol;
extern DWORD dwWaveTime;
extern BOOL SoundAvailable(UINT uDeviceID);
extern BOOL SoundGetDeviceID(UINT *puDeviceID);
extern BOOL SoundOpen(UINT uDeviceID);
extern VOID SoundClose(VOID);
extern VOID SoundOut(CHIPSET* w, WORD wOut);
extern VOID SoundBeep(DWORD dwFrequency, DWORD dwDuration);
// DDEserv.c
extern HDDEDATA CALLBACK DdeCallback(UINT, UINT, HCONV, HSZ, HSZ, HDDEDATA, DWORD, DWORD);
// Dismem.c
extern BOOL SetMemRomType(BYTE cCurrentRomType);
extern BOOL SetMemMapType(enum MEM_MAPPING eType);
extern enum MEM_MAPPING GetMemMapType(VOID);
extern BOOL GetMemAvail(enum MEM_MAPPING eType);
extern DWORD GetMemDataSize(VOID);
extern DWORD GetMemDataMask(VOID);
extern BYTE GetMemNib(DWORD *p);
extern VOID GetMemPeek(BYTE *a, DWORD d, UINT s);
// Disasm.c
extern BOOL disassembler_mode;
extern BOOL disassembler_symb;
extern DWORD disassemble(DWORD addr, LPTSTR out);
// Symbfile.c
extern BOOL RplTableEmpty(VOID);
extern BOOL RplLoadTable(LPCTSTR lpszFilename);
extern VOID RplDeleteTable(VOID);
extern LPCTSTR RplGetName(DWORD dwAddr);
extern BOOL RplGetAddr(LPCTSTR lpszName, DWORD *pdwAddr);
// Serial.c
extern BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort);
extern VOID CommClose(VOID);
extern VOID CommSetBaud(VOID);
extern BOOL UpdateUSRQ(VOID);
extern VOID CommTxBRK(VOID);
extern VOID CommTransmit(VOID);
extern VOID CommReceive(VOID);
// Cursor.c
extern HCURSOR CreateHandCursor(VOID);
#if defined _USRDLL // DLL version
// Emu48dll.c
extern VOID (CALLBACK *pEmuDocumentNotify)(LPCTSTR lpszFilename);
extern BOOL DLLCreateWnd(LPCTSTR lpszFilename, LPCTSTR lpszPort2Name);
extern BOOL DLLDestroyWnd(VOID);
// Symbfile.c
#define RplGetName(a) NULL // for linking
#endif
// Message Boxes
static __inline int InfoMessage(LPCTSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_OK|MB_ICONINFORMATION|MB_SETFOREGROUND);}
static __inline int AbortMessage(LPCTSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);}
static __inline int YesNoMessage(LPCTSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_YESNO|MB_ICONEXCLAMATION|MB_SETFOREGROUND);}
static __inline int YesNoCancelMessage(LPCTSTR szMessage,UINT uStyle) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_YESNOCANCEL|MB_ICONEXCLAMATION|MB_SETFOREGROUND|uStyle);}
// Missing Win32 API calls
static __inline LPTSTR DuplicateString(LPCTSTR szString)
{
UINT uLength = lstrlen(szString) + 1;
LPTSTR szDup = (LPTSTR) malloc(uLength*sizeof(szDup[0]));
lstrcpy(szDup,szString);
return szDup;
}
#define SCREENHEIGHT (cCurrentRomType=='Q' ? 80 : 64) // CdB for HP: add apples display management
#define SCREENHEIGHTREAL ((cCurrentRomType=='Q') ? (80-Chipset.d0size) : 64)
#define MAINSCREENHEIGHT (((Chipset.lcounter) == 0) ? SCREENHEIGHTREAL : SCREENHEIGHTREAL-64+((Chipset.lcounter)+1))
#define MENUHEIGHT (Chipset.lcounter==0?0:64-(Chipset.lcounter+1))

638
app/src/main/cpp/EMU48DLL.C Normal file
View file

@ -0,0 +1,638 @@
/*
* Emu48Dll.c
*
* This file is part of Emu48
*
* Copyright (C) 2000 Christoph Gießelink
*
*/
#include "pch.h"
#include "resource.h"
#include "Emu48.h"
#include "io.h"
#include "kml.h"
#include "debugger.h"
#include "Emu48Dll.h"
static LPCTSTR pArgv[3]; // command line memory
static ATOM classAtom = INVALID_ATOM; // window class atom
static HACCEL hAccel; // accelerator table
static HSZ hszService, hszTopic; // variables for DDE server
extern LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
// callback function notify document filename
VOID (CALLBACK *pEmuDocumentNotify)(LPCTSTR lpszFilename) = NULL;
// callback function notify Emu48 closed
static VOID (CALLBACK *pEmuClose)(VOID) = NULL;
//################
//#
//# Public internal functions
//#
//################
//
// DllMain
//
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
BOOL bSucc = TRUE;
if (fdwReason == DLL_PROCESS_ATTACH)
{
WNDCLASS wc;
wc.style = CS_BYTEALIGNCLIENT;
wc.lpfnWndProc = (WNDPROC)MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstDLL;
wc.hIcon = LoadIcon(hApp, MAKEINTRESOURCE(IDI_EMU48));
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
wc.lpszClassName = _T("CEmu48");
VERIFY(bSucc = ((classAtom = RegisterClass(&wc)) != INVALID_ATOM));
}
if (fdwReason == DLL_PROCESS_DETACH)
{
if (INVALID_ATOM != classAtom)
{
VERIFY(UnregisterClass(MAKEINTATOM(classAtom),hinstDLL));
classAtom = INVALID_ATOM;
}
}
return bSucc;
UNREFERENCED_PARAMETER(lpvReserved);
}
//
// DLLCreateWnd
//
BOOL DLLCreateWnd(LPCTSTR lpszFilename, LPCTSTR lpszPort2Name)
{
typedef DWORD (WINAPI *LPFN_STIP)(HANDLE hThread,DWORD dwIdealProcessor);
RECT rectWindow;
DWORD dwThreadId;
LPFN_STIP fnSetThreadIdealProcessor;
DWORD dwProcessor;
BOOL bFileExist = FALSE; // state file don't exist
hApp = GetModuleHandle(_T("EMU48.DLL"));
if (hApp == NULL) return TRUE;
nArgc = 1; // no argument
if (lpszFilename[0])
{
// try to open given filename
HANDLE hFile = CreateFile(lpszFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (bFileExist = (hFile != INVALID_HANDLE_VALUE))
CloseHandle(hFile);
ppArgv = pArgv; // command line arguments
nArgc = 2; // one argument: state file, no port2 file
pArgv[1] = lpszFilename; // name of state file
if (lpszPort2Name) // port2 filename
{
nArgc = 3; // two arguments: state file, port2 file
pArgv[2] = lpszPort2Name; // name of port2 file
}
}
// read emulator settings
GetCurrentDirectory(ARRAYSIZEOF(szCurrentDirectory),szCurrentDirectory);
ReadSettings();
// Create window
rectWindow.left = 0;
rectWindow.top = 0;
rectWindow.right = 256;
rectWindow.bottom = 0;
AdjustWindowRect(&rectWindow, WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_OVERLAPPED, TRUE);
hWnd = CreateWindow(MAKEINTATOM(classAtom),_T("Emu48"),
WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_OVERLAPPED,
CW_USEDEFAULT, CW_USEDEFAULT,
rectWindow.right - rectWindow.left,
rectWindow.bottom - rectWindow.top,
NULL,NULL,hApp,NULL
);
if (hWnd == NULL)
{
return TRUE;
}
VERIFY(hAccel = LoadAccelerators(hApp,MAKEINTRESOURCE(IDR_MENU)));
// remove debugger menu entry from resource
DeleteMenu(GetMenu(hWnd),ID_TOOL_DEBUG,MF_BYCOMMAND);
// initialization
EmuClearAllBreakpoints();
QueryPerformanceFrequency(&lFreq); // init high resolution counter
szCurrentKml[0] = 0; // no KML file selected
SetSpeed(bRealSpeed); // set speed
MruInit(0); // init MRU entries
// create shutdown auto event handle
hEventShutdn = CreateEvent(NULL,FALSE,FALSE,NULL);
if (hEventShutdn == NULL)
{
DestroyWindow(hWnd);
return TRUE;
}
// create debugger auto event handle
hEventDebug = CreateEvent(NULL,FALSE,FALSE,NULL);
if (hEventDebug == NULL)
{
CloseHandle(hEventShutdn); // close shutdown event handle
DestroyWindow(hWnd);
return TRUE;
}
nState = SM_RUN; // init state must be <> nNextState
nNextState = SM_INVALID; // go into invalid state
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&WorkerThread, NULL, CREATE_SUSPENDED, &dwThreadId);
if (hThread == NULL)
{
CloseHandle(hEventDebug); // close debugger event handle
CloseHandle(hEventShutdn); // close event handle
DestroyWindow(hWnd);
return TRUE;
}
// SetThreadIdealProcessor() is available since Windows NT4.0
fnSetThreadIdealProcessor = (LPFN_STIP) GetProcAddress(GetModuleHandle(_T("kernel32")),
"SetThreadIdealProcessor");
// bind Saturn CPU emulation thread to current ideal processor
dwProcessor = (fnSetThreadIdealProcessor != NULL) // running on NT4.0 or later
? fnSetThreadIdealProcessor(hThread,MAXIMUM_PROCESSORS) // get ideal processor no.
: 0; // select 1st processor
// on multiprocessor machines for QueryPerformanceCounter()
VERIFY(SetThreadAffinityMask(hThread,(DWORD_PTR) (1 << dwProcessor)));
ResumeThread(hThread); // start thread
while (nState!=nNextState) Sleep(0); // wait for thread initialized
idDdeInst = 0; // initialize DDE server
if (DdeInitialize(&idDdeInst,(PFNCALLBACK) &DdeCallback,
APPCLASS_STANDARD |
CBF_FAIL_EXECUTES | CBF_FAIL_ADVISES |
CBF_SKIP_REGISTRATIONS | CBF_SKIP_UNREGISTRATIONS,0))
{
TerminateThread(hThread, 0); // kill emulation thread
CloseHandle(hEventDebug); // close debugger event handle
CloseHandle(hEventShutdn); // close event handle
DestroyWindow(hWnd);
return TRUE;
}
// init clipboard format and name service
uCF_HpObj = RegisterClipboardFormat(_T(CF_HPOBJ));
hszService = DdeCreateStringHandle(idDdeInst,szAppName,0);
hszTopic = DdeCreateStringHandle(idDdeInst,szTopic,0);
DdeNameService(idDdeInst,hszService,NULL,DNS_REGISTER);
SoundOpen(uWaveDevId); // open waveform-audio output device
_ASSERT(hWnd != NULL);
_ASSERT(hWindowDC != NULL);
szBufferFilename[0] = 0;
if (bFileExist) // open existing file
{
lstrcpyn(szBufferFilename,ppArgv[1],ARRAYSIZEOF(szBufferFilename));
}
if (nArgc == 1) // no argument
{
ReadLastDocument(szBufferFilename,ARRAYSIZEOF(szBufferFilename));
}
if (szBufferFilename[0]) // given default document
{
TCHAR szTemp[MAX_PATH+8] = _T("Loading ");
RECT rectClient;
_ASSERT(hWnd != NULL);
VERIFY(GetClientRect(hWnd,&rectClient));
GetCutPathName(szBufferFilename,&szTemp[8],MAX_PATH,rectClient.right/11);
SetWindowTitle(szTemp);
if (OpenDocument(szBufferFilename))
{
MruAdd(szCurrentFilename);
ShowWindow(hWnd,SW_SHOWNORMAL);
goto start;
}
}
SetWindowTitle(_T("New Document"));
ShowWindow(hWnd,SW_SHOWNORMAL);
if (NewDocument())
{
if (nArgc >= 2)
SaveDocumentAs(ppArgv[1]);
else
SetWindowTitle(_T("Untitled"));
goto start;
}
DestroyWindow(hWnd); // clean up system
return TRUE;
start:
if (bStartupBackup) SaveBackup(); // make a RAM backup at startup
if (pbyRom) SwitchToState(SM_RUN);
return FALSE;
}
//
// DLLDestroyWnd
//
BOOL DLLDestroyWnd(VOID)
{
LPTSTR lpFilePart;
// clean up DDE server
DdeNameService(idDdeInst, hszService, NULL, DNS_UNREGISTER);
DdeFreeStringHandle(idDdeInst, hszService);
DdeFreeStringHandle(idDdeInst, hszTopic);
DdeUninitialize(idDdeInst);
SoundClose(); // close waveform-audio output device
// get full path name of szCurrentFilename
if (GetFullPathName(szCurrentFilename,ARRAYSIZEOF(szBufferFilename),szBufferFilename,&lpFilePart) == 0)
szBufferFilename[0] = 0; // no last document name
WriteLastDocument(szBufferFilename); // save last document setting
WriteSettings(); // save variable settings
CloseHandle(hThread); // close emulation thread handle
CloseHandle(hEventShutdn); // close shutdown event handle
CloseHandle(hEventDebug); // close debugger event handle
_ASSERT(nState == SM_RETURN); // emulation thread down?
ResetDocument();
ResetBackup();
MruCleanup();
_ASSERT(pbyRom == NULL); // rom file unmapped
_ASSERT(pbyPort2 == NULL); // port2 file unmapped
_ASSERT(pKml == NULL); // KML script not closed
_ASSERT(szTitle == NULL); // freed allocated memory
_ASSERT(hPalette == NULL); // freed resource memory
if (pEmuClose) pEmuClose(); // call notify function
return FALSE;
}
//################
//#
//# Public external functions
//#
//################
/****************************************************************************
* EmuCreate
*****************************************************************************
*
* @func start Emu48 and load Ram file into emulator, if Ram file don't
* exist create a new one and save it under the given name
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error
*
****************************************************************************/
DECLSPEC BOOL CALLBACK EmuCreate(
LPCTSTR lpszFilename) // @parm String with RAM filename
{
return DLLCreateWnd(lpszFilename, NULL);
}
/****************************************************************************
* EmuCreateEx
*****************************************************************************
*
* @func start Emu48 and load Ram and Port2 file into emulator, if Ram file
* don't exist create a new one and save it under the given name
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error
*
****************************************************************************/
DECLSPEC BOOL CALLBACK EmuCreateEx(
LPCTSTR lpszFilename, // @parm String with RAM filename
LPCTSTR lpszPort2Name) // @parm String with Port2 filename
// or NULL for using name inside INI file
{
return DLLCreateWnd(lpszFilename, lpszPort2Name);
}
/****************************************************************************
* EmuDestroy
*****************************************************************************
*
* @func close Emu48, free all memory
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error
*
****************************************************************************/
DECLSPEC BOOL CALLBACK EmuDestroy(VOID)
{
if (hWnd == NULL) return TRUE; // Emu48 closed
// close Emu48 via exit
SendMessage(hWnd,WM_SYSCOMMAND,SC_CLOSE,0);
return FALSE;
}
/****************************************************************************
* EmuAcceleratorTable
*****************************************************************************
*
* @func load accelerator table of emulator
*
* @xref none
*
* @rdesc HACCEL: handle of the loaded accelerator table
*
****************************************************************************/
DECLSPEC HACCEL CALLBACK EmuAcceleratorTable(
HWND *phEmuWnd) // @parm return of emulator window handle
{
*phEmuWnd = hWnd;
return hAccel;
}
/****************************************************************************
* EmuCallBackClose
*****************************************************************************
*
* @func init CallBack handler to notify caller when Emu48 window close
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
DECLSPEC VOID CALLBACK EmuCallBackClose(
VOID (CALLBACK *EmuClose)(VOID)) // @parm CallBack function notify caller Emu48 closed
{
pEmuClose = EmuClose; // set new handler
return;
}
/****************************************************************************
* EmuCallBackDocumentNotify
*****************************************************************************
*
* @func init CallBack handler to notify caller for actual document file
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
DECLSPEC VOID CALLBACK EmuCallBackDocumentNotify(
VOID (CALLBACK *EmuDocumentNotify)(LPCTSTR lpszFilename)) // @parm CallBack function notify document filename
{
pEmuDocumentNotify = EmuDocumentNotify; // set new handler
return;
}
/****************************************************************************
* EmuLoadRamFile
*****************************************************************************
*
* @func load Ram file into emulator
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error (old file reloaded)
*
****************************************************************************/
DECLSPEC BOOL CALLBACK EmuLoadRamFile(
LPCTSTR lpszFilename) // @parm String with RAM filename
{
BOOL bErr;
if (pbyRom) SwitchToState(SM_INVALID); // stop emulation thread
bErr = !OpenDocument(lpszFilename); // load state file
if (pbyRom) SwitchToState(SM_RUN); // restart emulation thread
return bErr;
}
/****************************************************************************
* EmuSaveRamFile
*****************************************************************************
*
* @func save the current emulator Ram to file
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error (old file reloaded)
*
****************************************************************************/
DECLSPEC BOOL CALLBACK EmuSaveRamFile(VOID)
{
BOOL bErr;
if (pbyRom == NULL) return TRUE; // fail
SwitchToState(SM_INVALID); // stop emulation thread
bErr = !SaveDocument(); // save current state file
SwitchToState(SM_RUN); // restart emulation thread
return bErr;
}
/****************************************************************************
* EmuLoadObject
*****************************************************************************
*
* @func load object file to stack
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error
*
****************************************************************************/
DECLSPEC BOOL CALLBACK EmuLoadObject(
LPCTSTR lpszObjectFilename) // @parm String with object filename
{
HANDLE hFile;
DWORD dwFileSizeLow;
DWORD dwFileSizeHigh;
LPBYTE lpBuf;
WORD wError = S_ERR_BINARY; // set into error state
SuspendDebugger(); // suspend debugger
bDbgAutoStateCtrl = FALSE; // disable automatic debugger state control
if (!(Chipset.IORam[BITOFFSET]&DON)) // calculator off, turn on
{
KeyboardEvent(TRUE,0,0x8000);
Sleep(dwWakeupDelay);
KeyboardEvent(FALSE,0,0x8000);
Sleep(dwWakeupDelay);
// wait for sleep mode
while(Chipset.Shutdn == FALSE) Sleep(0);
}
if (nState != SM_RUN) goto cancel; // emulator must run to load on object
if (WaitForSleepState()) goto cancel; // wait for cpu SHUTDN then sleep state
_ASSERT(nState == SM_SLEEP);
hFile = CreateFile(lpszObjectFilename,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
SwitchToState(SM_RUN); // run state
goto cancel;
}
dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
if (dwFileSizeHigh != 0)
{ // file is too large.
SwitchToState(SM_RUN); // run state
CloseHandle(hFile);
goto cancel;
}
lpBuf = malloc(dwFileSizeLow*2);
if (lpBuf == NULL)
{
SwitchToState(SM_RUN); // run state
CloseHandle(hFile);
goto cancel;
}
ReadFile(hFile, lpBuf+dwFileSizeLow, dwFileSizeLow, &dwFileSizeHigh, NULL);
CloseHandle(hFile);
wError = WriteStack(1,lpBuf,dwFileSizeLow);
free(lpBuf);
SwitchToState(SM_RUN); // run state
while (nState!=nNextState) Sleep(0);
_ASSERT(nState == SM_RUN);
KeyboardEvent(TRUE,0,0x8000);
Sleep(dwWakeupDelay);
KeyboardEvent(FALSE,0,0x8000);
while(Chipset.Shutdn == FALSE) Sleep(0);
cancel:
bDbgAutoStateCtrl = TRUE; // enable automatic debugger state control
ResumeDebugger();
return wError != S_ERR_NO;
}
/****************************************************************************
* EmuSaveObject
*****************************************************************************
*
* @func save object on stack to file
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error
*
****************************************************************************/
DECLSPEC BOOL CALLBACK EmuSaveObject(
LPCTSTR lpszObjectFilename) // @parm String with object filename
{
BOOL bErr;
if (nState != SM_RUN) return TRUE; // emulator must run to load on object
if (WaitForSleepState()) return TRUE; // wait for cpu SHUTDN then sleep state
_ASSERT(nState == SM_SLEEP);
bErr = !SaveObject(lpszObjectFilename);
SwitchToState(SM_RUN);
return bErr;
}
/****************************************************************************
* EmuCalculatorType
*****************************************************************************
*
* @func get ID of current calculator type
*
* @xref none
*
* @rdesc BYTE: '6' = HP38G with 64KB RAM
* 'A' = HP38G
* 'E' = HP39/40G
* 'S' = HP48SX
* 'G' = HP48GX
* 'X' = HP49G
* 'P' = HP39G+
* '2' = HP48GII
* 'Q' = HP49G+
*
****************************************************************************/
DECLSPEC BYTE CALLBACK EmuCalculatorType(VOID)
{
return Chipset.type;
}
/****************************************************************************
* EmuSimulateKey
*****************************************************************************
*
* @func simulate a key action
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
DECLSPEC VOID CALLBACK EmuSimulateKey(
BOOL bKeyState, // @parm TRUE = pressed, FALSE = released
UINT out, // @parm key out line
UINT in) // @parm key in line
{
KeyboardEvent(bKeyState,out,in);
}
/****************************************************************************
* EmuPressOn
*****************************************************************************
*
* @func press On key (emulation must run)
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
DECLSPEC VOID CALLBACK EmuPressOn(
BOOL bKeyState) // @parm TRUE = pressed, FALSE = released
{
KeyboardEvent(bKeyState,0,0x8000);
}

642
app/src/main/cpp/EMU48DLL.H Normal file
View file

@ -0,0 +1,642 @@
/*
* Emu48Dll.h
*
* This file is part of Emu48
*
* Copyright (C) 2000 Christoph Gießelink
*
*/
#define DECLSPEC __declspec(dllexport)
//////////////////////////////////
//
// breakpoint type definitions
//
//////////////////////////////////
#define BP_EXEC 0x01 // code breakpoint
#define BP_READ 0x02 // read memory breakpoint
#define BP_WRITE 0x04 // write memory breakpoint
#define BP_RPL 0x08 // RPL breakpoint
#define BP_ACCESS (BP_READ|BP_WRITE) // read/write memory breakpoint
#define BP_ROM 0x8000 // absolute ROM adress breakpoint
//////////////////////////////////
//
// REGISTER ACCESS API
//
//////////////////////////////////
#define EMU_REGISTER_PC 0
#define EMU_REGISTER_D0 1
#define EMU_REGISTER_D1 2
#define EMU_REGISTER_DUMMY 3
#define EMU_REGISTER_AL 4
#define EMU_REGISTER_AH 5
#define EMU_REGISTER_BL 6
#define EMU_REGISTER_BH 7
#define EMU_REGISTER_CL 8
#define EMU_REGISTER_CH 9
#define EMU_REGISTER_DL 10
#define EMU_REGISTER_DH 11
#define EMU_REGISTER_R0L 12
#define EMU_REGISTER_R0H 13
#define EMU_REGISTER_R1L 14
#define EMU_REGISTER_R1H 15
#define EMU_REGISTER_R2L 16
#define EMU_REGISTER_R2H 17
#define EMU_REGISTER_R3L 18
#define EMU_REGISTER_R3H 19
#define EMU_REGISTER_R4L 20
#define EMU_REGISTER_R4H 21
#define EMU_REGISTER_R5L 22
#define EMU_REGISTER_R5H 23
#define EMU_REGISTER_R6L 24
#define EMU_REGISTER_R6H 25
#define EMU_REGISTER_R7L 26
#define EMU_REGISTER_R7H 27
#define EMU_REGISTER_FLAGS 28
#define EMU_REGISTER_OUT 29
#define EMU_REGISTER_IN 30
#define EMU_REGISTER_VIEW1 31
#define EMU_REGISTER_VIEW2 32
#define EMU_REGISTER_RSTKP 63
#define EMU_REGISTER_RSTK0 64
#define EMU_REGISTER_RSTK1 65
#define EMU_REGISTER_RSTK2 66
#define EMU_REGISTER_RSTK3 67
#define EMU_REGISTER_RSTK4 68
#define EMU_REGISTER_RSTK5 69
#define EMU_REGISTER_RSTK6 70
#define EMU_REGISTER_RSTK7 71
#define EMU_REGISTER_CLKL 72
#define EMU_REGISTER_CLKH 73
#define EMU_REGISTER_CRC 74
/**
* "FLAGS" register format :
*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ST |S|x|x|x|K|I|C|M| HST | P |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* M : Mode (0:Hex, 1:Dec)
* C : Carry
* I : Interrupt pending
* K : KDN Interrupts Enabled
* S : Shutdn Flag (read only)
* x : reserved
*/
/****************************************************************************
* EmuCreate
*****************************************************************************
*
* @func start Emu48 and load Ram file into emulator, if Ram file don't
* exist create a new one and save it under the given name
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error
*
****************************************************************************/
EXTERN_C DECLSPEC BOOL CALLBACK EmuCreate(
LPCTSTR lpszFilename); // @parm String with RAM filename
/****************************************************************************
* EmuCreateEx
*****************************************************************************
*
* @func start Emu48 and load Ram and Port2 file into emulator, if Ram file
* don't exist create a new one and save it under the given name
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error
*
****************************************************************************/
EXTERN_C DECLSPEC BOOL CALLBACK EmuCreateEx(
LPCTSTR lpszFilename, // @parm String with RAM filename
LPCTSTR lpszPort2Name); // @parm String with Port2 filename
// or NULL for using name inside INI file
/****************************************************************************
* EmuDestroy
*****************************************************************************
*
* @func close Emu48, free all memory
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error
*
****************************************************************************/
EXTERN_C DECLSPEC BOOL CALLBACK EmuDestroy(VOID);
/****************************************************************************
* EmuAcceleratorTable
*****************************************************************************
*
* @func load accelerator table of emulator
*
* @xref none
*
* @rdesc HACCEL: handle of the loaded accelerator table
*
****************************************************************************/
EXTERN_C DECLSPEC HACCEL CALLBACK EmuAcceleratorTable(
HWND *phEmuWnd); // @parm return of emulator window handle
/****************************************************************************
* EmuCallBackClose
*****************************************************************************
*
* @func init CallBack handler to notify caller when Emu48 window close
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuCallBackClose(
VOID (CALLBACK *EmuClose)(VOID)); // @parm CallBack function notify caller Emu48 closed
/****************************************************************************
* EmuCallBackDocumentNotify
*****************************************************************************
*
* @func init CallBack handler to notify caller for actual document file
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuCallBackDocumentNotify(
VOID (CALLBACK *EmuDocumentNotify)(LPCTSTR lpszFilename)); // @parm CallBack function notify document filename
/****************************************************************************
* EmuLoadRamFile
*****************************************************************************
*
* @func load Ram file into emulator
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error (old file reloaded)
*
****************************************************************************/
EXTERN_C DECLSPEC BOOL CALLBACK EmuLoadRamFile(
LPCTSTR lpszFilename); // @parm String with RAM filename
/****************************************************************************
* EmuSaveRamFile
*****************************************************************************
*
* @func save the current emulator Ram to file
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error (old file reloaded)
*
****************************************************************************/
EXTERN_C DECLSPEC BOOL CALLBACK EmuSaveRamFile(VOID);
/****************************************************************************
* EmuLoadObject
*****************************************************************************
*
* @func load object file to stack
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error
*
****************************************************************************/
EXTERN_C DECLSPEC BOOL CALLBACK EmuLoadObject(
LPCTSTR lpszObjectFilename); // @parm String with object filename
/****************************************************************************
* EmuSaveObject
*****************************************************************************
*
* @func save object on stack to file
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error
*
****************************************************************************/
EXTERN_C DECLSPEC BOOL CALLBACK EmuSaveObject(
LPCTSTR lpszObjectFilename); // @parm String with object filename
/****************************************************************************
* EmuCalculatorType
*****************************************************************************
*
* @func get ID of current calculator type
*
* @xref none
*
* @rdesc BYTE: '6' = HP38G with 64KB RAM
* 'A' = HP38G
* 'E' = HP39/40G
* 'S' = HP48SX
* 'G' = HP48GX
* 'X' = HP49G
* 'P' = HP39G+
* '2' = HP48GII
* 'Q' = HP49G+
*
****************************************************************************/
EXTERN_C DECLSPEC BYTE CALLBACK EmuCalculatorType(VOID);
/****************************************************************************
* EmuSimulateKey
*****************************************************************************
*
* @func simulate a key action
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuSimulateKey(
BOOL bKeyState, // @parm TRUE = pressed, FALSE = released
UINT out, // @parm key out line
UINT in); // @parm key in line
/****************************************************************************
* EmuPressOn
*****************************************************************************
*
* @func press On key (emulation must run)
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuPressOn(
BOOL bKeyState); // @parm TRUE = pressed, FALSE = released
/****************************************************************************
* EmuInitLastInstr
*****************************************************************************
*
* @func init a circular buffer area for saving the last instruction
* addresses
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error
*
****************************************************************************/
EXTERN_C DECLSPEC BOOL CALLBACK EmuInitLastInstr(
WORD wNoInstr, // @parm number of saved instructions,
// 0 = frees the memory buffer
DWORD *pdwArray); // @parm pointer to linear array
/****************************************************************************
* EmuGetLastInstr
*****************************************************************************
*
* @func return number of valid entries in the last instruction array,
* each entry contents a PC address, array[0] contents the oldest,
* array[*pwNoEntries-1] the last PC address
*
* @xref none
*
* @rdesc BOOL: FALSE = OK, TRUE = Error
*
****************************************************************************/
EXTERN_C DECLSPEC BOOL CALLBACK EmuGetLastInstr(
WORD *pwNoEntries); // @parm return number of valid entries in array
/****************************************************************************
* EmuRun
*****************************************************************************
*
* @func run emulation
*
* @xref none
*
* @rdesc BOOL: FALSE = OK
* TRUE = Error, Emu48 is running
*
****************************************************************************/
EXTERN_C DECLSPEC BOOL CALLBACK EmuRun(VOID);
/****************************************************************************
* EmuRunPC
*****************************************************************************
*
* @func run emulation until stop address
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuRunPC(
DWORD dwAddressPC); // @parm breakpoint address
/****************************************************************************
* EmuStep
*****************************************************************************
*
* @func execute one ASM instruction and return to caller
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuStep(VOID);
/****************************************************************************
* EmuStepOver
*****************************************************************************
*
* @func execute one ASM instruction but skip GOSUB, GOSUBL, GOSBVL
* subroutines
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuStepOver(VOID);
/****************************************************************************
* EmuStepOut
*****************************************************************************
*
* @func run emulation until a RTI, RTN, RTNC, RTNCC, RTNNC, RTNSC, RTNSXN,
* RTNYES instruction is found above the current stack level
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuStepOut(VOID);
/****************************************************************************
* EmuStop
*****************************************************************************
*
* @func break emulation
*
* @xref none
*
* @rdesc BOOL: FALSE = OK
* TRUE = Error, no debug notify handler
*
****************************************************************************/
EXTERN_C DECLSPEC BOOL CALLBACK EmuStop(VOID);
/****************************************************************************
* EmuCallBackDebugNotify
*****************************************************************************
*
* @func init CallBack handler to notify caller on debugger breakpoint
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuCallBackDebugNotify(
VOID (CALLBACK *EmuDbgNotify)(INT nBreaktype)); // @parm CallBack function notify Debug breakpoint
/****************************************************************************
* EmuCallBackStackNotify
*****************************************************************************
*
* @func init CallBack handler to notify caller on hardware stack change;
* if the CallBack function return TRUE, emulation stops behind the
* opcode changed hardware stack content, otherwise, if the CallBack
* function return FALSE, no breakpoint is set
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuCallBackStackNotify(
BOOL (CALLBACK *EmuStackNotify)(VOID)); // @parm CallBack function notify stack changed
/****************************************************************************
* EmuGetRegister
*****************************************************************************
*
* @func read a 32 bit register
*
* @xref none
*
* @rdesc DWORD: 32 bit value of register
*
****************************************************************************/
EXTERN_C DECLSPEC DWORD CALLBACK EmuGetRegister(
UINT uRegister); // @parm index of register
/****************************************************************************
* EmuSetRegister
*****************************************************************************
*
* @func write a 32 bit register
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuSetRegister(
UINT uRegister, // @parm index of register
DWORD dwValue); // @parm new 32 bit value
/****************************************************************************
* EmuGetMem
*****************************************************************************
*
* @func read one nibble from the specified mapped address
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuGetMem(
DWORD dwMapAddr, // @parm mapped address of Saturn CPU
BYTE *pbyValue); // @parm readed nibble
/****************************************************************************
* EmuSetMem
*****************************************************************************
*
* @func write one nibble to the specified mapped address
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuSetMem(
DWORD dwMapAddr, // @parm mapped address of Saturn CPU
BYTE byValue); // @parm nibble to write
/****************************************************************************
* EmuGetRom
*****************************************************************************
*
* @func return size and base address of mapped ROM
*
* @xref none
*
* @rdesc LPBYTE: base address of ROM (pointer to original data)
*
****************************************************************************/
EXTERN_C DECLSPEC LPBYTE CALLBACK EmuGetRom(
DWORD *pdwRomSize); // @parm return size of ROM in nibbles
/****************************************************************************
* EmuSetBreakpoint
*****************************************************************************
*
* @func set ASM code/data breakpoint
*
* @xref none
*
* @rdesc BOOL: TRUE = Error, Breakpoint table full
* FALSE = OK, Breakpoint set
*
****************************************************************************/
EXTERN_C DECLSPEC BOOL CALLBACK EmuSetBreakpoint(
DWORD dwAddress, // @parm breakpoint address to set
UINT nBreakpointType); // @parm breakpoint type to set
/****************************************************************************
* EmuClearBreakpoint
*****************************************************************************
*
* @func clear ASM code/data breakpoint
*
* @xref none
*
* @rdesc BOOL: TRUE = Error, Breakpoint not found
* FALSE = OK, Breakpoint cleared
*
****************************************************************************/
EXTERN_C DECLSPEC BOOL CALLBACK EmuClearBreakpoint(
DWORD dwAddress, // @parm breakpoint address to clear
UINT nBreakpointType); // @parm breakpoint type to clear
/****************************************************************************
* EmuClearAllBreakpoints
*****************************************************************************
*
* @func clear all breakpoints
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuClearAllBreakpoints(VOID);
/****************************************************************************
* EmuEnableNop3Breakpoint
*****************************************************************************
*
* @func enable/disable NOP3 breakpoint
* stop emulation at Opcode 420 for GOC + (next line)
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuEnableNop3Breakpoint(
BOOL bEnable); // @parm stop on NOP3 opcode
/****************************************************************************
* EmuEnableDocodeBreakpoint
*****************************************************************************
*
* @func enable/disable DOCODE breakpoint
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuEnableDoCodeBreakpoint(
BOOL bEnable); // @parm stop on DOCODE entry
/****************************************************************************
* EmuEnableRplBreakpoint
*****************************************************************************
*
* @func enable/disable RPL breakpoint
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuEnableRplBreakpoint(
BOOL bEnable); // @parm stop on RPL exit
/****************************************************************************
* EmuEnableSkipInterruptCode
*****************************************************************************
*
* @func enable/disable skip single step execution inside the interrupt
* handler, this option has no effect on code and data breakpoints
*
* @xref none
*
* @rdesc VOID
*
****************************************************************************/
EXTERN_C DECLSPEC VOID CALLBACK EmuEnableSkipInterruptCode(
BOOL bEnable); // @parm TRUE = skip code instructions
// inside interrupt service routine

645
app/src/main/cpp/ENGINE.C Normal file
View file

@ -0,0 +1,645 @@
/*
* engine.c
*
* This file is part of Emu48
*
* Copyright (C) 1995 Sebastien Carlier
*
*/
#include "pch.h"
#include "Emu48.h"
#include "Opcodes.h"
#include "io.h"
#include "debugger.h"
#define SAMPLE 16384 // speed adjust sample frequency
BOOL bInterrupt = FALSE;
UINT nState = SM_INVALID;
UINT nNextState = SM_RUN;
BOOL bEnableSlow = TRUE; // slow down is enabled
BOOL bRealSpeed = FALSE;
BOOL bKeySlow = FALSE; // slow down for key emulation
BOOL bSoundSlow = FALSE; // slow down for sound emulation
UINT nOpcSlow = 0; // no. of opcodes to slow down
BOOL bCommInit = FALSE; // COM port not open
CHIPSET Chipset;
TCHAR szSerialWire[16]; // devicename for wire port
TCHAR szSerialIr[16]; // devicename for IR port
DWORD dwSXCycles = 82; // SX cpu cycles in interval
DWORD dwGXCycles = 123; // GX cpu cycles in interval
DWORD dwGPCycles = 123*3; // g+ cpu cycles in interval // CdB for HP: add apples display management
DWORD dwG2Cycles = 123*2; // gII cpu cycles in interval // CdB for HP: add apples display management
// variables for debugger engine
HANDLE hEventDebug; // event handle to stop cpu thread
BOOL bDbgAutoStateCtrl = TRUE; // debugger suspend control by SwitchToState()
INT nDbgState = DBG_OFF; // state of debugger
BOOL bDbgNOP3 = FALSE; // halt on NOP3 (#420 opcode)
BOOL bDbgRPL = FALSE; // halt on RPL entry
BOOL bDbgCode = FALSE; // halt on DOCODE entry
BOOL bDbgSkipInt = FALSE; // execute interrupt handler
DWORD dwDbgStopPC = -1; // stop address for goto cursor
DWORD dwDbgRplPC = -1; // stop address for RPL breakpoint
DWORD dwDbgRstkp; // stack recursion level of step over end
DWORD dwDbgRstk; // possible return address
DWORD *pdwInstrArray = NULL; // last instruction array
WORD wInstrSize = 256; // size of last instruction array
WORD wInstrWp; // write pointer of instruction array
WORD wInstrRp; // read pointer of instruction array
static INT nDbgRplBreak = BN_ASM; // flag for RPL breakpoint detection
static INT nDbgOldState = DBG_OFF; // old state of debugger for suspend/resume
static BOOL bCpuSlow = FALSE; // enable/disable real speed
static DWORD dwEDbgT2 = 0; // debugger timer2 emulation
static DWORD dwEDbgCycles = 0; // debugger cycle counter
static DWORD dwOldCyc; // cpu cycles at last event
static DWORD dwSpeedRef; // timer value at last event
static DWORD dwTickRef; // sample timer ticks
#include "Ops.h"
// save last instruction in circular instruction buffer
static __inline VOID SaveInstrAddr(DWORD dwAddr)
{
EnterCriticalSection(&csDbgLock);
{
if (pdwInstrArray) // circular buffer allocated
{
pdwInstrArray[wInstrWp] = dwAddr;
wInstrWp = (wInstrWp + 1) % wInstrSize;
if (wInstrWp == wInstrRp)
wInstrRp = (wInstrRp + 1) % wInstrSize;
}
}
LeaveCriticalSection(&csDbgLock);
return;
}
static __inline VOID Debugger(VOID) // debugger part
{
LARGE_INTEGER lDummyInt; // sample timer ticks
BOOL bStopEmulation;
LPBYTE I = FASTPTR(Chipset.pc); // get opcode stream
UpdateDbgCycleCounter(); // update 64 bit cpu cycle counter
SaveInstrAddr(Chipset.pc); // save pc in last instruction buffer
nDbgRplBreak = BN_ASM; // notify ASM breakpoint
// check for code breakpoints
bStopEmulation = CheckBreakpoint(Chipset.pc, 1, BP_EXEC);
// check for memory breakpoints, opcode #14x or #15x
if (I[0] == 0x1 && (I[1] == 0x4 || I[1] == 0x5))
{
DWORD dwData = (I[2] & 0x1) ? Chipset.d1 : Chipset.d0;
UINT nType = (I[2] & 0x2) ? BP_READ : BP_WRITE;
DWORD dwRange;
if (I[1] == 0x4) // B,A
{
dwRange = (I[2] & 0x8) ? 2 : 5;
}
else // number of nibbles, (P,WP,XS,X,S,M,W)
{
dwRange = (I[2] & 0x8) ? (I[3]+1) : (F_l[I[3]]);
}
#if defined DEBUG_DEBUGGER
{
TCHAR buffer[256];
wsprintf(buffer,_T("Memory breakpoint %.5lx, %u\n",dwData,dwRange));
OutputDebugString(buffer);
}
#endif
bStopEmulation |= CheckBreakpoint(dwData, dwRange, nType);
}
// check for step cursor
bStopEmulation |= (dwDbgStopPC == Chipset.pc);
// NOP3, opcode #420 (GOC)
if (bDbgNOP3 && I[0] == 0x4 && I[1] == 0x2 && I[2] == 0x0)
bStopEmulation = TRUE;
// stop on first instruction of DOCODE object
if (bDbgCode && (Chipset.pc == 0x02DDE || Chipset.pc == 0x02E3C))
{
// return address
DWORD dwAddr = Chipset.rstk[(Chipset.rstkp-1)&7];
_ASSERT(I[0] == 0 && I[1] == 1); // stopped at RTN opcode
if (MapData(dwAddr) != M_ROM) // address not in ROM
dwDbgStopPC = dwAddr; // then stop
}
// check for RPL breakpoint
if (dwDbgRplPC == Chipset.pc)
{
dwDbgRplPC = -1;
nDbgRplBreak = bStopEmulation ? BN_ASM_BT : BN_RPL;
bStopEmulation = TRUE;
}
// RPL breakpoints, PC=(A), opcode #808C or PC=(C), opcode #808E
if (I[0] == 0x8 && I[1] == 0x0 && I[2] == 0x8 && (I[3] == 0xC || I[3] == 0xE ))
{
// get next RPL entry
DWORD dwAddr = Npack((I[3] == 0xC) ? Chipset.A : Chipset.C,5);
if (bDbgRPL || CheckBreakpoint(dwAddr, 1, BP_RPL))
{
BYTE byRplPtr[5];
Npeek(byRplPtr,dwAddr,5); // get PC address of next opcode
dwDbgRplPC = Npack(byRplPtr,5); // set RPL breakpoint
}
}
// step over interrupt execution
if (bDbgSkipInt && !bStopEmulation && !Chipset.inte)
return;
// check for step into
bStopEmulation |= (nDbgState == DBG_STEPINTO);
// check for step over
bStopEmulation |= (nDbgState == DBG_STEPOVER) && dwDbgRstkp == Chipset.rstkp;
// check for step out, something was popped from hardware stack
if (nDbgState == DBG_STEPOUT && dwDbgRstkp == Chipset.rstkp)
{
_ASSERT(bStopEmulation == FALSE);
if ((bStopEmulation = (Chipset.pc == dwDbgRstk)) == FALSE)
{
// it was C=RSTK, check for next object popped from hardware stack
dwDbgRstkp = (Chipset.rstkp-1)&7;
dwDbgRstk = Chipset.rstk[dwDbgRstkp];
}
}
if (bStopEmulation) // stop condition
{
StopTimers(); // hold timer values when emulator is stopped
if (Chipset.IORam[TIMER2_CTRL]&RUN) // check if timer running
{
if (dwEDbgT2 == Chipset.t2)
{
// cpu cycles for one timer2 tick elapsed
if ((DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwEDbgCycles
>= (SAMPLE / 8192) * (DWORD) T2CYCLES)
{
--Chipset.t2;
// adjust cycles reference
dwEDbgCycles += (SAMPLE / 8192) * T2CYCLES;
}
}
else // new timer2 value
{
// new cycle reference
dwEDbgCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
}
// check rising edge of Bit 8 of timer2
if ((dwEDbgT2 & 0x100) == 0 && (Chipset.t2 & 0x100) != 0)
Chipset.t1 = (Chipset.t1 - 1) & 0xF;
}
dwEDbgT2 = Chipset.t2; // timer2 check reference value
// redraw debugger window and stop
NotifyDebugger(nDbgRplBreak);
WaitForSingleObject(hEventDebug,INFINITE);
StartTimers(); // continue timers
if (nDbgState >= DBG_OFF) // if debugger is active
{
Chipset.Shutdn = FALSE;
Chipset.bShutdnWake = FALSE;
}
// init slow down part
dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
QueryPerformanceCounter(&lDummyInt);
dwSpeedRef = lDummyInt.LowPart;
}
return;
}
VOID SuspendDebugger(VOID)
{
// auto control enabled, emulation halted by debugger
if (bDbgAutoStateCtrl && nDbgState > DBG_OFF)
{
nDbgOldState = nDbgState; // save old state
nDbgState = DBG_SUSPEND; // suspend state
SetEvent(hEventDebug); // exit debugger
}
return;
}
VOID ResumeDebugger(VOID)
{
// auto control enabled, debugger is suspended
if (bDbgAutoStateCtrl && nDbgState == DBG_SUSPEND)
{
// active RPL breakpoint
if (nDbgRplBreak) dwDbgRplPC = Chipset.pc;
nDbgState = nDbgOldState; // set to old debugger state
if (Chipset.Shutdn) // inside shutdown
SetEvent(hEventShutdn); // leave it to call debugger
}
return;
}
static __inline VOID CheckDisp(BOOL bSync)
{
if (disp == 0) return; // no display update need
// update display when drawing top line or display is off
if (bSync && GetLineCounter() != 0x3F && (Chipset.IORam[0x00]&8))
return;
_ASSERT((disp & DISP_POINTER) == 0); // display pointer already updated
if (disp & DISP_MAIN) UpdateMainDisplay();
if (disp & DISP_MENUE) UpdateMenuDisplay();
_ASSERT((disp & DISP_ANNUN) == 0); // annunciators already updated
disp = 0; // display updated
return;
}
static __inline VOID AdjustSpeed(VOID) // adjust emulation speed
{
// emulation slow down
if ( bEnableSlow
&& (bCpuSlow || bKeySlow || bSoundSlow || nOpcSlow > 0))
{
DWORD dwCycles,dwTicks;
EnterCriticalSection(&csSlowLock);
{
// cycles elapsed for next check
if ((dwCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF)-dwOldCyc) >= (DWORD) T2CYCLES)
{
LARGE_INTEGER lAct;
do
{
VERIFY(QueryPerformanceCounter(&lAct));
// get time difference
dwTicks = lAct.LowPart - dwSpeedRef;
}
// ticks elapsed or negative number (workaround for QueryPerformanceCounter() in Win2k)
while (dwTicks <= dwTickRef || (dwTicks & 0x80000000) != 0);
dwOldCyc += T2CYCLES; // adjust cycles reference
dwSpeedRef += dwTickRef; // adjust reference time
}
if (nOpcSlow > 0) --nOpcSlow; // decr. slow down opcode counter
}
LeaveCriticalSection(&csSlowLock);
}
return;
}
VOID CheckSerial(VOID)
{
// COM port closed and serial on
if (bCommInit == FALSE && (Chipset.IORam[IOC] & SON) != 0)
{
bCommInit = CommOpen(szSerialWire,szSerialIr); // open COM ports
}
// COM port opened and serial off
if (bCommInit == TRUE && (Chipset.IORam[IOC] & SON) == 0)
{
CommClose(); // close COM port
bCommInit = FALSE;
}
return;
}
VOID InitAdjustSpeed(VOID)
{
// slow down function not initalized
if (!bEnableSlow || (!bCpuSlow && !bKeySlow && !bSoundSlow && nOpcSlow == 0))
{
LARGE_INTEGER lTime; // sample timer ticks
// save reference cycles
dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
QueryPerformanceCounter(&lTime); // get timer ticks
dwSpeedRef = lTime.LowPart; // save reference time
}
return;
}
VOID AdjKeySpeed(VOID) // slow down key repeat
{
WORD i;
BOOL bKey;
bKey = FALSE; // search for a pressed key
for (i = 0;i < ARRAYSIZEOF(Chipset.Keyboard_Row) && !bKey;++i)
bKey = (Chipset.Keyboard_Row[i] != 0);
EnterCriticalSection(&csSlowLock);
{
if (bKey) // key pressed
{
InitAdjustSpeed(); // init variables if necessary
}
bKeySlow = bKey; // save new state
}
LeaveCriticalSection(&csSlowLock);
return;
}
VOID SetSpeed(BOOL bAdjust) // set emulation speed
{
EnterCriticalSection(&csSlowLock);
{
if (bAdjust) // switch to real speed
{
InitAdjustSpeed(); // init variables if necessary
}
bCpuSlow = bAdjust; // save emulation speed
}
LeaveCriticalSection(&csSlowLock);
return;
}
VOID UpdateKdnBit(VOID) // update KDN bit
{
if ( Chipset.intk
&& (Chipset.IORam[TIMER2_CTRL]&RUN) != 0
&& (DWORD) (Chipset.cycles & 0xFFFFFFFF) - Chipset.dwKdnCycles > (DWORD) T2CYCLES * 16)
IOBit(SRQ2,KDN,Chipset.in != 0);
return;
}
BOOL WaitForSleepState(VOID) // wait for cpu SHUTDN then sleep state
{
DWORD dwRefTime;
SuspendDebugger(); // suspend debugger
dwRefTime = timeGetTime();
// wait for the SHUTDN command with 1.5 sec timeout
while (timeGetTime() - dwRefTime < 1500L && !Chipset.Shutdn)
Sleep(0);
if (Chipset.Shutdn) // not timeout, cpu is down
SwitchToState(SM_SLEEP); // go to sleep state
else
ResumeDebugger(); // timeout, resume to debugger
return SM_SLEEP != nNextState; // state not changed, emulator was busy
}
UINT SwitchToState(UINT nNewState)
{
UINT nOldState = nState;
if (nState == nNewState) return nOldState;
switch (nState)
{
case SM_RUN: // Run
switch (nNewState)
{
case SM_INVALID: // -> Invalid
nNextState = SM_INVALID;
if (Chipset.Shutdn)
SetEvent(hEventShutdn);
else
bInterrupt = TRUE;
SuspendDebugger(); // suspend debugger
while (nState!=nNextState) Sleep(0);
break;
case SM_RETURN: // -> Return
DisableDebugger(); // disable debugger
nNextState = SM_INVALID;
if (Chipset.Shutdn)
SetEvent(hEventShutdn);
else
bInterrupt = TRUE;
while (nState!=nNextState) Sleep(0);
nNextState = SM_RETURN;
SetEvent(hEventShutdn);
WaitForSingleObject(hThread,INFINITE);
break;
case SM_SLEEP: // -> Sleep
nNextState = SM_SLEEP;
bInterrupt = TRUE; // exit main loop
SuspendDebugger(); // suspend debugger
SetEvent(hEventShutdn); // exit shutdown
while (nState!=nNextState) Sleep(0);
bInterrupt = FALSE;
ResetEvent(hEventDebug);
ResetEvent(hEventShutdn);
break;
}
break;
case SM_INVALID: // Invalid
switch (nNewState)
{
case SM_RUN: // -> Run
nNextState = SM_RUN;
// don't enter opcode loop on interrupt request
bInterrupt = Chipset.Shutdn || Chipset.SoftInt;
ResumeDebugger();
SetEvent(hEventShutdn);
while (nState!=nNextState) Sleep(0);
break;
case SM_RETURN: // -> Return
DisableDebugger(); // disable debugger
nNextState = SM_RETURN;
SetEvent(hEventShutdn);
WaitForSingleObject(hThread,INFINITE);
break;
case SM_SLEEP: // -> Sleep
nNextState = SM_SLEEP;
SetEvent(hEventShutdn);
while (nState!=nNextState) Sleep(0);
break;
}
break;
case SM_SLEEP: // Sleep
switch (nNewState)
{
case SM_RUN: // -> Run
nNextState = SM_RUN;
// don't enter opcode loop on interrupt request
bInterrupt = (nDbgState == DBG_OFF) && (Chipset.Shutdn || Chipset.SoftInt);
ResumeDebugger();
SetEvent(hEventShutdn); // leave sleep state
break;
case SM_INVALID: // -> Invalid
nNextState = SM_INVALID;
SetEvent(hEventShutdn);
while (nState!=nNextState) Sleep(0);
break;
case SM_RETURN: // -> Return
DisableDebugger(); // disable debugger
nNextState = SM_INVALID;
SetEvent(hEventShutdn);
while (nState!=nNextState) Sleep(0);
nNextState = SM_RETURN;
SetEvent(hEventShutdn);
WaitForSingleObject(hThread,INFINITE);
break;
}
break;
}
return nOldState;
}
UINT WorkerThread(LPVOID pParam)
{
LARGE_INTEGER lDummyInt; // sample timer ticks
QueryPerformanceFrequency(&lDummyInt); // init timer ticks
lDummyInt.QuadPart /= SAMPLE; // calculate sample ticks
dwTickRef = lDummyInt.LowPart; // sample timer ticks
_ASSERT(dwTickRef); // tick resolution error
loop:
while (nNextState == SM_INVALID) // go into invalid state
{
OnToolMacroStop(); // close open keyboard macro handler
CommClose(); // close COM port
bCommInit = FALSE; // COM port not open
nState = SM_INVALID; // in invalid state
WaitForSingleObject(hEventShutdn,INFINITE);
if (nNextState == SM_RETURN) // go into return state
{
nState = SM_RETURN; // in return state
return 0; // kill thread
}
CheckSerial(); // test if UART on
}
while (nNextState == SM_RUN)
{
if (nState != SM_RUN)
{
nState = SM_RUN;
// clear port2 status bits
Chipset.cards_status &= ~(PORT2_PRESENT | PORT2_WRITE);
if (pbyPort2 || Port2) // card plugged in port2
{
Chipset.cards_status |= PORT2_PRESENT;
if (bPort2Writeable) // is card writeable
Chipset.cards_status |= PORT2_WRITE;
}
// card detection off and timer running
if ((Chipset.IORam[CARDCTL] & ECDT) == 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0)
{
BOOL bNINT2 = Chipset.IORam[SRQ1] == 0 && (Chipset.IORam[SRQ2] & LSRQ) == 0;
BOOL bNINT = (Chipset.IORam[CARDCTL] & SMP) == 0;
// state of CDT2
bNINT2 = bNINT2 && (Chipset.cards_status & (P2W|P2C)) != P2C;
// state of CDT1
bNINT = bNINT && (Chipset.cards_status & (P1W|P1C)) != P1C;
IOBit(SRQ2,NINT2,bNINT2);
IOBit(SRQ2,NINT,bNINT);
}
RomSwitch(Chipset.Bank_FF); // select HP49G ROM bank and update memory mapping
UpdateContrast(Chipset.contrast);
UpdateDisplayPointers();
UpdateMainDisplay();
UpdateMenuDisplay();
RefreshDisp0(); // CdB for HP: add apples display management
UpdateAnnunciators();
// init speed reference
dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
QueryPerformanceCounter(&lDummyInt);
dwSpeedRef = lDummyInt.LowPart;
SetHP48Time(); // update HP48 time & date
// start display counter/update engine
StartDisplay((BYTE)(((Chipset.IORam[LINECOUNT+1]<<4)|Chipset.IORam[LINECOUNT])&0x3F));
StartBatMeasure(); // start battery measurement
StartTimers();
}
PCHANGED;
while (!bInterrupt)
{
if (nDbgState > DBG_OFF) // debugger active
{
Debugger();
// if suspended skip next opcode execution
if (nDbgState == DBG_SUSPEND)
{
if (Chipset.Shutdn) break;
continue;
}
}
EvalOpcode(FASTPTR(Chipset.pc)); // execute opcode
// check for display update in BW mode
if (!bGrayscale) CheckDisp(!Chipset.Shutdn);
AdjustSpeed(); // adjust emulation speed
}
bInterrupt = FALSE; // be sure to reenter opcode loop
// enter SHUTDN handler only in RUN mode
if (Chipset.Shutdn && !(nDbgState == DBG_STEPINTO || nDbgState == DBG_STEPOVER))
{
if (!Chipset.SoftInt) // ignore SHUTDN on interrupt request
WaitForSingleObject(hEventShutdn,INFINITE);
else
Chipset.bShutdnWake = TRUE; // waked by interrupt
if (Chipset.bShutdnWake) // waked up by timer, keyboard or serial
{
Chipset.bShutdnWake = FALSE;
Chipset.Shutdn = FALSE;
// init speed reference
dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
QueryPerformanceCounter(&lDummyInt);
dwSpeedRef = lDummyInt.LowPart;
nOpcSlow = 0; // no opcodes to slow down
}
}
if (Chipset.SoftInt)
{
Chipset.SoftInt = FALSE;
if (Chipset.inte)
{
Chipset.inte = FALSE;
rstkpush(Chipset.pc);
Chipset.pc = 0xf;
}
}
}
_ASSERT(nNextState != SM_RUN);
StopDisplay(); // stop display counter/update
StopBatMeasure(); // stop battery measurement
StopTimers();
while (nNextState == SM_SLEEP) // go into sleep state
{
nState = SM_SLEEP; // in sleep state
WaitForSingleObject(hEventShutdn,INFINITE);
}
goto loop;
UNREFERENCED_PARAMETER(pParam);
}

100
app/src/main/cpp/EXTERNAL.C Normal file
View file

@ -0,0 +1,100 @@
/*
* external.c
*
* This file is part of Emu48
*
* Copyright (C) 1995 Sebastien Carlier
* Copyright (C) 2005 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
#include "ops.h"
//| 38G | 39G | 40G | 48SX | 48GX | 49G | Name
//#F0E4F #80F0F #80F0F #706D2 #80850 #80F0F =SFLAG53_56
// memory address for flags -53 to -56
// CdB for HP: add apples beep management
#define SFLAG53_56 ( (cCurrentRomType=='6') \
? 0xE0E4F \
: ( (cCurrentRomType=='A') \
? 0xF0E4F \
: ( (cCurrentRomType!='E' && cCurrentRomType!='X' && cCurrentRomType!='P' && cCurrentRomType!='2' && cCurrentRomType!='Q') \
? ( (cCurrentRomType=='S') \
? 0x706D2 \
: 0x80850 \
) \
: 0x80F0F \
) \
) \
)
VOID External(CHIPSET* w) // Beep patch
{
BYTE fbeep;
DWORD freq,dur;
freq = Npack(w->D,5); // frequency in Hz
dur = Npack(w->C,5); // duration in ms
Nread(&fbeep,SFLAG53_56,1); // fetch system flags -53 to -56
w->carry = TRUE; // setting of no beep
if (!(fbeep & 0x8) && freq) // bit -56 clear and frequency > 0 Hz
{
if (freq > 4400) freq = 4400; // high limit of HP (SX)
SoundBeep(freq,dur); // beeping
// estimate cpu cycles for beeping time (2MHz / 4MHz)
w->cycles += dur * ((cCurrentRomType=='S') ? 2000 : 4000);
// original routine return with...
w->P = 0; // P=0
w->intk = TRUE; // INTON
w->carry = FALSE; // RTNCC
}
w->pc = rstkpop();
return;
}
VOID RCKBp(CHIPSET* w) // ROM Check Beep patch
{
DWORD dw2F,dwCpuFreq;
DWORD freq,dur;
BYTE f,d;
f = w->C[1]; // f = freq ctl
d = w->C[0]; // d = duration ctl
if (cCurrentRomType == 'S') // Clarke chip with 48S ROM
{
// CPU strobe frequency @ RATE 14 = 1.97MHz
dwCpuFreq = ((14 + 1) * 524288) >> 2;
dw2F = f * 126 + 262; // F=f*63+131
}
else // York chip with 48G and later ROM
{
// CPU strobe frequency @ RATE 27 = 3.67MHz
// CPU strobe frequency @ RATE 29 = 3.93MHz
dwCpuFreq = ((27 + 1) * 524288) >> 2;
dw2F = f * 180 + 367; // F=f*90+183.5
}
freq = dwCpuFreq / dw2F;
dur = (dw2F * (256 - 16 * d)) * 1000 / 2 / dwCpuFreq;
if (freq > 4400) freq = 4400; // high limit of HP
SoundBeep(freq,dur); // beeping
// estimate cpu cycles for beeping time (2MHz / 4MHz)
w->cycles += dur * ((cCurrentRomType=='S') ? 2000 : 4000);
w->P = 0; // P=0
w->carry = FALSE; // RTNCC
w->pc = rstkpop();
return;
}

778
app/src/main/cpp/FETCH.C Normal file
View file

@ -0,0 +1,778 @@
/*
* fetch.c
*
* This file is part of Emu48
*
* Copyright (C) 1999 Christoph Gießelink
*
*/
#include "pch.h"
#include "Opcodes.h"
#define F 0xFF // F = function
typedef const struct
{
LPCVOID pLnk;
const DWORD dwTyp;
} JMPTAB, *PJMPTAB;
// jump tables
static JMPTAB oF_[] =
{
(LPCVOID) oF0, F,
(LPCVOID) oF1, F,
(LPCVOID) oF2, F,
(LPCVOID) oF3, F,
(LPCVOID) oF4, F,
(LPCVOID) oF5, F,
(LPCVOID) oF6, F,
(LPCVOID) oF7, F,
(LPCVOID) oF8, F,
(LPCVOID) oF9, F,
(LPCVOID) oFA, F,
(LPCVOID) oFB, F,
(LPCVOID) oFC, F,
(LPCVOID) oFD, F,
(LPCVOID) oFE, F,
(LPCVOID) oFF, F
};
static JMPTAB oE_[] =
{
(LPCVOID) oE0, F,
(LPCVOID) oE1, F,
(LPCVOID) oE2, F,
(LPCVOID) oE3, F,
(LPCVOID) oE4, F,
(LPCVOID) oE5, F,
(LPCVOID) oE6, F,
(LPCVOID) oE7, F,
(LPCVOID) oE8, F,
(LPCVOID) oE9, F,
(LPCVOID) oEA, F,
(LPCVOID) oEB, F,
(LPCVOID) oEC, F,
(LPCVOID) oED, F,
(LPCVOID) oEE, F,
(LPCVOID) oEF, F
};
static JMPTAB oD_[] =
{
(LPCVOID) oD0, F,
(LPCVOID) oD1, F,
(LPCVOID) oD2, F,
(LPCVOID) oD3, F,
(LPCVOID) oD4, F,
(LPCVOID) oD5, F,
(LPCVOID) oD6, F,
(LPCVOID) oD7, F,
(LPCVOID) oD8, F,
(LPCVOID) oD9, F,
(LPCVOID) oDA, F,
(LPCVOID) oDB, F,
(LPCVOID) oDC, F,
(LPCVOID) oDD, F,
(LPCVOID) oDE, F,
(LPCVOID) oDF, F
};
static JMPTAB oC_[] =
{
(LPCVOID) oC0, F,
(LPCVOID) oC1, F,
(LPCVOID) oC2, F,
(LPCVOID) oC3, F,
(LPCVOID) oC4, F,
(LPCVOID) oC5, F,
(LPCVOID) oC6, F,
(LPCVOID) oC7, F,
(LPCVOID) oC8, F,
(LPCVOID) oC9, F,
(LPCVOID) oCA, F,
(LPCVOID) oCB, F,
(LPCVOID) oCC, F,
(LPCVOID) oCD, F,
(LPCVOID) oCE, F,
(LPCVOID) oCF, F
};
static JMPTAB oBb_[] =
{
(LPCVOID) oBb0, F,
(LPCVOID) oBb1, F,
(LPCVOID) oBb2, F,
(LPCVOID) oBb3, F,
(LPCVOID) oBb4, F,
(LPCVOID) oBb5, F,
(LPCVOID) oBb6, F,
(LPCVOID) oBb7, F,
(LPCVOID) oBb8, F,
(LPCVOID) oBb9, F,
(LPCVOID) oBbA, F,
(LPCVOID) oBbB, F,
(LPCVOID) oBbC, F,
(LPCVOID) oBbD, F,
(LPCVOID) oBbE, F,
(LPCVOID) oBbF, F
};
static JMPTAB oBa_[] =
{
(LPCVOID) oBa0, F,
(LPCVOID) oBa1, F,
(LPCVOID) oBa2, F,
(LPCVOID) oBa3, F,
(LPCVOID) oBa4, F,
(LPCVOID) oBa5, F,
(LPCVOID) oBa6, F,
(LPCVOID) oBa7, F,
(LPCVOID) oBa8, F,
(LPCVOID) oBa9, F,
(LPCVOID) oBaA, F,
(LPCVOID) oBaB, F,
(LPCVOID) oBaC, F,
(LPCVOID) oBaD, F,
(LPCVOID) oBaE, F,
(LPCVOID) oBaF, F
};
static JMPTAB oB_[] =
{
(LPCVOID) oBa_, 2,
(LPCVOID) oBa_, 2,
(LPCVOID) oBa_, 2,
(LPCVOID) oBa_, 2,
(LPCVOID) oBa_, 2,
(LPCVOID) oBa_, 2,
(LPCVOID) oBa_, 2,
(LPCVOID) oBa_, 2,
(LPCVOID) oBb_, 2,
(LPCVOID) oBb_, 2,
(LPCVOID) oBb_, 2,
(LPCVOID) oBb_, 2,
(LPCVOID) oBb_, 2,
(LPCVOID) oBb_, 2,
(LPCVOID) oBb_, 2,
(LPCVOID) oBb_, 2
};
static JMPTAB oAb_[] =
{
(LPCVOID) oAb0, F,
(LPCVOID) oAb1, F,
(LPCVOID) oAb2, F,
(LPCVOID) oAb3, F,
(LPCVOID) oAb4, F,
(LPCVOID) oAb5, F,
(LPCVOID) oAb6, F,
(LPCVOID) oAb7, F,
(LPCVOID) oAb8, F,
(LPCVOID) oAb9, F,
(LPCVOID) oAbA, F,
(LPCVOID) oAbB, F,
(LPCVOID) oAbC, F,
(LPCVOID) oAbD, F,
(LPCVOID) oAbE, F,
(LPCVOID) oAbF, F
};
static JMPTAB oAa_[] =
{
(LPCVOID) oAa0, F,
(LPCVOID) oAa1, F,
(LPCVOID) oAa2, F,
(LPCVOID) oAa3, F,
(LPCVOID) oAa4, F,
(LPCVOID) oAa5, F,
(LPCVOID) oAa6, F,
(LPCVOID) oAa7, F,
(LPCVOID) oAa8, F,
(LPCVOID) oAa9, F,
(LPCVOID) oAaA, F,
(LPCVOID) oAaB, F,
(LPCVOID) oAaC, F,
(LPCVOID) oAaD, F,
(LPCVOID) oAaE, F,
(LPCVOID) oAaF, F
};
static JMPTAB oA_[] =
{
(LPCVOID) oAa_, 2,
(LPCVOID) oAa_, 2,
(LPCVOID) oAa_, 2,
(LPCVOID) oAa_, 2,
(LPCVOID) oAa_, 2,
(LPCVOID) oAa_, 2,
(LPCVOID) oAa_, 2,
(LPCVOID) oAa_, 2,
(LPCVOID) oAb_, 2,
(LPCVOID) oAb_, 2,
(LPCVOID) oAb_, 2,
(LPCVOID) oAb_, 2,
(LPCVOID) oAb_, 2,
(LPCVOID) oAb_, 2,
(LPCVOID) oAb_, 2,
(LPCVOID) oAb_, 2
};
static JMPTAB o9b_[] =
{
(LPCVOID) o9b0, F,
(LPCVOID) o9b1, F,
(LPCVOID) o9b2, F,
(LPCVOID) o9b3, F,
(LPCVOID) o9b4, F,
(LPCVOID) o9b5, F,
(LPCVOID) o9b6, F,
(LPCVOID) o9b7, F,
(LPCVOID) o9b8, F,
(LPCVOID) o9b9, F,
(LPCVOID) o9bA, F,
(LPCVOID) o9bB, F,
(LPCVOID) o9bC, F,
(LPCVOID) o9bD, F,
(LPCVOID) o9bE, F,
(LPCVOID) o9bF, F
};
static JMPTAB o9a_[] =
{
(LPCVOID) o9a0, F,
(LPCVOID) o9a1, F,
(LPCVOID) o9a2, F,
(LPCVOID) o9a3, F,
(LPCVOID) o9a4, F,
(LPCVOID) o9a5, F,
(LPCVOID) o9a6, F,
(LPCVOID) o9a7, F,
(LPCVOID) o9a8, F,
(LPCVOID) o9a9, F,
(LPCVOID) o9aA, F,
(LPCVOID) o9aB, F,
(LPCVOID) o9aC, F,
(LPCVOID) o9aD, F,
(LPCVOID) o9aE, F,
(LPCVOID) o9aF, F
};
static JMPTAB o9_[] =
{
(LPCVOID) o9a_, 2,
(LPCVOID) o9a_, 2,
(LPCVOID) o9a_, 2,
(LPCVOID) o9a_, 2,
(LPCVOID) o9a_, 2,
(LPCVOID) o9a_, 2,
(LPCVOID) o9a_, 2,
(LPCVOID) o9a_, 2,
(LPCVOID) o9b_, 2,
(LPCVOID) o9b_, 2,
(LPCVOID) o9b_, 2,
(LPCVOID) o9b_, 2,
(LPCVOID) o9b_, 2,
(LPCVOID) o9b_, 2,
(LPCVOID) o9b_, 2,
(LPCVOID) o9b_, 2
};
static JMPTAB o8B_[] =
{
(LPCVOID) o8B0, F,
(LPCVOID) o8B1, F,
(LPCVOID) o8B2, F,
(LPCVOID) o8B3, F,
(LPCVOID) o8B4, F,
(LPCVOID) o8B5, F,
(LPCVOID) o8B6, F,
(LPCVOID) o8B7, F,
(LPCVOID) o8B8, F,
(LPCVOID) o8B9, F,
(LPCVOID) o8BA, F,
(LPCVOID) o8BB, F,
(LPCVOID) o8BC, F,
(LPCVOID) o8BD, F,
(LPCVOID) o8BE, F,
(LPCVOID) o8BF, F
};
static JMPTAB o8A_[] =
{
(LPCVOID) o8A0, F,
(LPCVOID) o8A1, F,
(LPCVOID) o8A2, F,
(LPCVOID) o8A3, F,
(LPCVOID) o8A4, F,
(LPCVOID) o8A5, F,
(LPCVOID) o8A6, F,
(LPCVOID) o8A7, F,
(LPCVOID) o8A8, F,
(LPCVOID) o8A9, F,
(LPCVOID) o8AA, F,
(LPCVOID) o8AB, F,
(LPCVOID) o8AC, F,
(LPCVOID) o8AD, F,
(LPCVOID) o8AE, F,
(LPCVOID) o8AF, F
};
static JMPTAB o81B_[] =
{
(LPCVOID) o_invalid4, F,
(LPCVOID) o81B1, F, // normally o_invalid4, beep patch, Apple: LOOP
(LPCVOID) o81B2, F,
(LPCVOID) o81B3, F,
(LPCVOID) o81B4, F,
(LPCVOID) o81B5, F,
(LPCVOID) o81B6, F,
(LPCVOID) o81B7, F,
(LPCVOID) o_invalid4, F, // Apple: SKPTOP
(LPCVOID) o_invalid4, F, // Apple: SKBOT
(LPCVOID) o_invalid4, F, // Apple: SKIP
(LPCVOID) o_invalid4, F, // Apple: SKPLEN
(LPCVOID) o_invalid4, F, // Apple: SKPID
(LPCVOID) o_invalid4, F, // Apple: $SEMI
(LPCVOID) o_invalid4, F, // Apple: DOCOL
(LPCVOID) o_invalid4, F
};
static JMPTAB o81Af2_[] =
{
(LPCVOID) o81Af20, F,
(LPCVOID) o81Af21, F,
(LPCVOID) o81Af22, F,
(LPCVOID) o81Af23, F,
(LPCVOID) o81Af24, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o81Af28, F,
(LPCVOID) o81Af29, F,
(LPCVOID) o81Af2A, F,
(LPCVOID) o81Af2B, F,
(LPCVOID) o81Af2C, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F
};
static JMPTAB o81Af1_[] =
{
(LPCVOID) o81Af10, F,
(LPCVOID) o81Af11, F,
(LPCVOID) o81Af12, F,
(LPCVOID) o81Af13, F,
(LPCVOID) o81Af14, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o81Af18, F,
(LPCVOID) o81Af19, F,
(LPCVOID) o81Af1A, F,
(LPCVOID) o81Af1B, F,
(LPCVOID) o81Af1C, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F
};
static JMPTAB o81Af0_[] =
{
(LPCVOID) o81Af00, F,
(LPCVOID) o81Af01, F,
(LPCVOID) o81Af02, F,
(LPCVOID) o81Af03, F,
(LPCVOID) o81Af04, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o81Af08, F,
(LPCVOID) o81Af09, F,
(LPCVOID) o81Af0A, F,
(LPCVOID) o81Af0B, F,
(LPCVOID) o81Af0C, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F
};
static JMPTAB o81A_[] =
{
(LPCVOID) o81Af0_, 5,
(LPCVOID) o81Af1_, 5,
(LPCVOID) o81Af2_, 5,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F
};
static JMPTAB o819_[] =
{
(LPCVOID) o819f0, F,
(LPCVOID) o819f1, F,
(LPCVOID) o819f2, F,
(LPCVOID) o819f3, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F
};
static JMPTAB o818_[] =
{
(LPCVOID) o818f0x, F,
(LPCVOID) o818f1x, F,
(LPCVOID) o818f2x, F,
(LPCVOID) o818f3x, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o818f8x, F,
(LPCVOID) o818f9x, F,
(LPCVOID) o818fAx, F,
(LPCVOID) o818fBx, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F,
(LPCVOID) o_invalid6, F
};
static JMPTAB o81_[] =
{
(LPCVOID) o810, F,
(LPCVOID) o811, F,
(LPCVOID) o812, F,
(LPCVOID) o813, F,
(LPCVOID) o814, F,
(LPCVOID) o815, F,
(LPCVOID) o816, F,
(LPCVOID) o817, F,
(LPCVOID) o818_, 4,
(LPCVOID) o819_, 4,
(LPCVOID) o81A_, 4,
(LPCVOID) o81B_, 3,
(LPCVOID) o81C, F,
(LPCVOID) o81D, F,
(LPCVOID) o81E, F,
(LPCVOID) o81F, F
};
static JMPTAB o8081_[] =
{
(LPCVOID) o80810, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F,
(LPCVOID) o_invalid5, F
};
static JMPTAB o808_[] =
{
(LPCVOID) o8080, F,
(LPCVOID) o8081_, 4,
(LPCVOID) o8082X, F,
(LPCVOID) o8083, F,
(LPCVOID) o8084n, F,
(LPCVOID) o8085n, F,
(LPCVOID) o8086n, F,
(LPCVOID) o8087n, F,
(LPCVOID) o8088n, F,
(LPCVOID) o8089n, F,
(LPCVOID) o808An, F,
(LPCVOID) o808Bn, F,
(LPCVOID) o808C, F,
(LPCVOID) o808D, F,
(LPCVOID) o808E, F,
(LPCVOID) o808F, F
};
static JMPTAB o80_[] =
{
(LPCVOID) o800, F,
(LPCVOID) o801, F,
(LPCVOID) o802, F,
(LPCVOID) o803, F,
(LPCVOID) o804, F,
(LPCVOID) o805, F,
(LPCVOID) o806, F,
(LPCVOID) o807, F,
(LPCVOID) o808_, 3,
(LPCVOID) o809, F,
(LPCVOID) o80A, F,
(LPCVOID) o80B, F,
(LPCVOID) o80Cn, F,
(LPCVOID) o80Dn, F,
(LPCVOID) o80E, F,
(LPCVOID) o80Fn, F
};
static JMPTAB o8_[] =
{
(LPCVOID) o80_, 2,
(LPCVOID) o81_, 2,
(LPCVOID) o82n, F,
(LPCVOID) o83n, F,
(LPCVOID) o84n, F,
(LPCVOID) o85n, F,
(LPCVOID) o86n, F,
(LPCVOID) o87n, F,
(LPCVOID) o88n, F,
(LPCVOID) o89n, F,
(LPCVOID) o8A_, 2,
(LPCVOID) o8B_, 2,
(LPCVOID) o8Cd4, F,
(LPCVOID) o8Dd5, F,
(LPCVOID) o8Ed4, F,
(LPCVOID) o8Fd5, F
};
static JMPTAB o15_[] =
{
(LPCVOID) o150a, F,
(LPCVOID) o151a, F,
(LPCVOID) o152a, F,
(LPCVOID) o153a, F,
(LPCVOID) o154a, F,
(LPCVOID) o155a, F,
(LPCVOID) o156a, F,
(LPCVOID) o157a, F,
(LPCVOID) o158x, F,
(LPCVOID) o159x, F,
(LPCVOID) o15Ax, F,
(LPCVOID) o15Bx, F,
(LPCVOID) o15Cx, F,
(LPCVOID) o15Dx, F,
(LPCVOID) o15Ex, F,
(LPCVOID) o15Fx, F
};
static JMPTAB o14_[] =
{
(LPCVOID) o140, F,
(LPCVOID) o141, F,
(LPCVOID) o142, F,
(LPCVOID) o143, F,
(LPCVOID) o144, F,
(LPCVOID) o145, F,
(LPCVOID) o146, F,
(LPCVOID) o147, F,
(LPCVOID) o148, F,
(LPCVOID) o149, F,
(LPCVOID) o14A, F,
(LPCVOID) o14B, F,
(LPCVOID) o14C, F,
(LPCVOID) o14D, F,
(LPCVOID) o14E, F,
(LPCVOID) o14F, F
};
static JMPTAB o13_[] =
{
(LPCVOID) o130, F,
(LPCVOID) o131, F,
(LPCVOID) o132, F,
(LPCVOID) o133, F,
(LPCVOID) o134, F,
(LPCVOID) o135, F,
(LPCVOID) o136, F,
(LPCVOID) o137, F,
(LPCVOID) o138, F,
(LPCVOID) o139, F,
(LPCVOID) o13A, F,
(LPCVOID) o13B, F,
(LPCVOID) o13C, F,
(LPCVOID) o13D, F,
(LPCVOID) o13E, F,
(LPCVOID) o13F, F
};
static JMPTAB o12_[] =
{
(LPCVOID) o120, F,
(LPCVOID) o121, F,
(LPCVOID) o122, F,
(LPCVOID) o123, F,
(LPCVOID) o124, F,
(LPCVOID) o_invalid3, F,
(LPCVOID) o_invalid3, F,
(LPCVOID) o_invalid3, F,
(LPCVOID) o128, F,
(LPCVOID) o129, F,
(LPCVOID) o12A, F,
(LPCVOID) o12B, F,
(LPCVOID) o12C, F,
(LPCVOID) o_invalid3, F,
(LPCVOID) o_invalid3, F,
(LPCVOID) o_invalid3, F
};
static JMPTAB o11_[] =
{
(LPCVOID) o110, F,
(LPCVOID) o111, F,
(LPCVOID) o112, F,
(LPCVOID) o113, F,
(LPCVOID) o114, F,
(LPCVOID) o_invalid3, F,
(LPCVOID) o_invalid3, F,
(LPCVOID) o_invalid3, F,
(LPCVOID) o118, F,
(LPCVOID) o119, F,
(LPCVOID) o11A, F,
(LPCVOID) o11B, F,
(LPCVOID) o11C, F,
(LPCVOID) o_invalid3, F,
(LPCVOID) o_invalid3, F,
(LPCVOID) o_invalid3, F
};
static JMPTAB o10_[] =
{
(LPCVOID) o100, F,
(LPCVOID) o101, F,
(LPCVOID) o102, F,
(LPCVOID) o103, F,
(LPCVOID) o104, F,
(LPCVOID) o_invalid3, F,
(LPCVOID) o_invalid3, F,
(LPCVOID) o_invalid3, F,
(LPCVOID) o108, F,
(LPCVOID) o109, F,
(LPCVOID) o10A, F,
(LPCVOID) o10B, F,
(LPCVOID) o10C, F,
(LPCVOID) o_invalid3, F,
(LPCVOID) o_invalid3, F,
(LPCVOID) o_invalid3, F
};
static JMPTAB o1_[] =
{
(LPCVOID) o10_, 2,
(LPCVOID) o11_, 2,
(LPCVOID) o12_, 2,
(LPCVOID) o13_, 2,
(LPCVOID) o14_, 2,
(LPCVOID) o15_, 2,
(LPCVOID) o16x, F,
(LPCVOID) o17x, F,
(LPCVOID) o18x, F,
(LPCVOID) o19d2, F,
(LPCVOID) o1Ad4, F,
(LPCVOID) o1Bd5, F,
(LPCVOID) o1Cx, F,
(LPCVOID) o1Dd2, F,
(LPCVOID) o1Ed4, F,
(LPCVOID) o1Fd5, F
};
static JMPTAB o0E_[] =
{
(LPCVOID) o0Ef0, F,
(LPCVOID) o0Ef1, F,
(LPCVOID) o0Ef2, F,
(LPCVOID) o0Ef3, F,
(LPCVOID) o0Ef4, F,
(LPCVOID) o0Ef5, F,
(LPCVOID) o0Ef6, F,
(LPCVOID) o0Ef7, F,
(LPCVOID) o0Ef8, F,
(LPCVOID) o0Ef9, F,
(LPCVOID) o0EfA, F,
(LPCVOID) o0EfB, F,
(LPCVOID) o0EfC, F,
(LPCVOID) o0EfD, F,
(LPCVOID) o0EfE, F,
(LPCVOID) o0EfF, F
};
static JMPTAB o0_[] =
{
(LPCVOID) o00, F,
(LPCVOID) o01, F,
(LPCVOID) o02, F,
(LPCVOID) o03, F,
(LPCVOID) o04, F,
(LPCVOID) o05, F,
(LPCVOID) o06, F,
(LPCVOID) o07, F,
(LPCVOID) o08, F,
(LPCVOID) o09, F,
(LPCVOID) o0A, F,
(LPCVOID) o0B, F,
(LPCVOID) o0C, F,
(LPCVOID) o0D, F,
(LPCVOID) o0E_, 3,
(LPCVOID) o0F, F
};
static JMPTAB o_[] =
{
(LPCVOID) o0_, 1,
(LPCVOID) o1_, 1,
(LPCVOID) o2n, F,
(LPCVOID) o3X, F,
(LPCVOID) o4d2, F,
(LPCVOID) o5d2, F,
(LPCVOID) o6d3, F,
(LPCVOID) o7d3, F,
(LPCVOID) o8_, 1,
(LPCVOID) o9_, 1,
(LPCVOID) oA_, 1,
(LPCVOID) oB_, 1,
(LPCVOID) oC_, 1,
(LPCVOID) oD_, 1,
(LPCVOID) oE_, 1,
(LPCVOID) oF_, 1
};
// opcode dispatcher
VOID EvalOpcode(LPBYTE I)
{
DWORD dwIndex = 0;
PJMPTAB pJmpTab = o_;
do
{
_ASSERT(I[dwIndex] <= 0xf); // found packed data
pJmpTab = &pJmpTab[I[dwIndex]]; // table entry by opcode
dwIndex = pJmpTab->dwTyp; // next pointer type
pJmpTab = (PJMPTAB) pJmpTab->pLnk; // next pointer to table/function
}
while (dwIndex != F); // reference to table? -> again
((VOID (*)(LPBYTE)) pJmpTab)(I); // call function
return;
}

2727
app/src/main/cpp/FILES.C Normal file

File diff suppressed because it is too large Load diff

754
app/src/main/cpp/I28F160.C Normal file
View file

@ -0,0 +1,754 @@
/*
* i28f160.c
*
* This file is part of Emu48
*
* Copyright (C) 2000 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
#include "i28f160.h"
#define ARRAYSIZEOF(a) (sizeof(a) / sizeof(a[0]))
// Flash Command Set
#define READ_ARRAY 0xFF
#define READ_ID_CODES 0x90
#define READ_QUERY 0x98
#define READ_STATUS_REG 0x70
#define CLEAR_STATUS_REG 0x50
#define WRITE_BUFFER 0xE8
#define WORD_BYTE_PROG1 0x40
#define WORD_BYTE_PROG2 0x10
#define BLOCK_ERASE 0x20
#define BLOCK_ERASE_SUSPEND 0xB0
#define BLOCK_ERASE_RESUME 0xD0
#define STS_CONFIG 0xB8
#define SET_CLR_BLOCK_LOCK 0x60
#define FULL_CHIP_ERASE 0x30
#define CONFIRM 0xD0
// Status Register Definition
#define WSMS 0x80 // WRITE STATE MACHINE STATUS
#define ESS 0x40 // ERASE SUSPEND STATUS
#define ECLBS 0x20 // ERASE AND CLEAR LOCK-BIT STATUS
#define BWSLBS 0x10 // PROGRAM AND SET LOCK-BIT STATUS
#define VPPS 0x08 // Vpp STATUS
#define BWSS 0x04 // PROGRAM SUSPEND STATUS
#define DPS 0x02 // DEVICE PROTECT STATUS
// Extended Status Register Definition
#define WBS 0x80 // WRITE BUFFER STATUS
// write state defines
#define WRS_DATA 0 // idle state
#define WRS_WR_BUFFER_N 1 // write buffer no. of data
#define WRS_WR_BUFFER_D 2 // write buffer data
#define WRS_WR_BUFFER_C 3 // write buffer confirm
#define WRS_WR_BYTE 4 // write byte/word
#define WRS_BLOCK_ERASE 5 // block erase
#define WRS_CHIP_ERASE 6 // full chip erase
#define WRS_STS_PIN_CONFIG 7 // STS pin Configuration
#define WRS_LOCK_BITS 8 // Set/Clear Block Lock-Bits
// read state defines
#define RDS_DATA 0 // data read
#define RDS_ID 1 // read identifier codes
#define RDS_QUERY 2 // read query
#define RDS_SR 3 // read status register
#define RDS_XSR 4 // read extended status register
// global data
WSMSET WSMset;
BOOL bWP = FALSE; // WP# = low, locked blocks cannot be erased
// function prototypes
// write function WSM state
static VOID WrStateIdle(BYTE a, DWORD d);
static VOID WrStateE8(DWORD d);
static VOID WrStateE8N(BYTE a, DWORD d);
static VOID WrStateE8D(BYTE a, DWORD d);
static VOID WrStateE8C(BYTE a, DWORD d);
static VOID WrState40(DWORD d);
static VOID WrState40D(BYTE a, DWORD d);
static VOID WrState20(DWORD d);
static VOID WrState20C(BYTE a, DWORD d);
static VOID WrState30(DWORD d);
static VOID WrState30C(BYTE a, DWORD d);
static VOID WrStateB8(DWORD d);
static VOID WrStateB8D(BYTE a, DWORD d);
static VOID WrState60(DWORD d);
static VOID WrState60D(BYTE a, DWORD d);
static VOID (*CONST fnWrState[])(BYTE a, DWORD d) =
{
WrStateIdle,
WrStateE8N, WrStateE8D, WrStateE8C,
WrState40D,
WrState20C,
WrState30C,
WrStateB8D,
WrState60D
};
// read function WSM state
static BYTE RdStateData(DWORD d);
static BYTE RdStateId(DWORD d);
static BYTE RdStateQuery(DWORD d);
static BYTE RdStateSR(DWORD d);
static BYTE RdStateXSR(DWORD d);
static BYTE (*CONST fnRdState[])(DWORD d) =
{
RdStateData, RdStateId, RdStateQuery, RdStateSR, RdStateXSR
};
// read query table
// device address A16-A1, A0 unused
static CONST BYTE byQueryTab[] =
{
// access with "Read Identifier Codes" command
// Identifier codes
0xB0, // 00, Manufacturer Code
0xD0, // 01, Device Code (16 Mbit)
0x00, // 02, Block Lock Configuration
0x02, // 03, ??
0x00, // 04, Reserved for vendor-specific information
0x00, // 05, "
0x00, // 06, "
0x00, // 07, "
0x00, // 08, "
0x00, // 09, "
0x00, // 0A, "
0x00, // 0B, "
0x00, // 0C, "
0x00, // 0D, "
0x00, // 0E, "
0x00, // 0F, "
// access with "Read Query" command
// CFI query identification string
0x51, // 10, Query-Unique ASCII string "Q"
0x52, // 11, Query-Unique ASCII string "R"
0x59, // 12, Query-Unique ASCII string "Y"
0x01, // 13, Primary Vendor Command Set and Control Interface ID CODE
0x00, // 14, "
0x31, // 15, Address for Primary Algorithm Extended Query Table
0x00, // 16, "
0x00, // 17, Alternate Vendor Command Set and Control Interface ID Code
0x00, // 18, "
0x00, // 19, Address for Secondary Algorithm Extended Query Table
0x00, // 1A, "
// System interface information
0x30, // 1B, Vcc Logic Supply Minimum Program/Erase Voltage (0x27 intel doc, 0x30 real chip)
0x55, // 1C, Vcc Logic Supply Maximum Program/Erase Voltage
0x30, // 1D, Vpp [Programming] Supply Minimum Program/Erase Voltage (0x27 intel doc, 0x30 real chip)
0x55, // 1E, Vpp [Programming] Supply Maximum Program/Erase Voltage
0x03, // 1F, Typical Time-Out per Single Byte/Word Program
0x06, // 20, Typical Time-Out for Max. Buffer Write
0x0A, // 21, Typical Time-Out per Individual Block Erase
0x0F, // 22, Typical Time-Out for Full Chip Erase
0x04, // 23, Maximum Time-Out for Byte/Word Program
0x04, // 24, Maximum Time-Out for Buffer Write
0x04, // 25, Maximum Time-Out per Individual Block Erase
0x04, // 26, Maximum Time-Out for Full Chip Erase
0x15, // 27, Device Size
0x02, // 28, Flash Device Interface Description
0x00, // 29, "
0x05, // 2A, Maximum Number of Bytes in Write Buffer
0x00, // 2B, "
0x01, // 2C, Number of Erase Block Regions within Device
0x1F, // 2D, Erase Block Region Information
0x00, // 2E, "
0x00, // 2F, "
0x01, // 30, "
// Intel-specific extended query table
0x50, // 31, Primary Extended Query Table, Unique ASCII string "P"
0x52, // 32, Primary Extended Query Table, Unique ASCII string "R"
0x49, // 33, Primary Extended Query Table, Unique ASCII string "I"
0x31, // 34, Major Version Number, ASCII
0x30, // 35, Minor Version Number, ASCII
0x0F, // 36, Optional Feature & Command Support
0x00, // 37, "
0x00, // 38, "
0x00, // 39, "
0x01, // 3A, Supported Functions after Suspend
0x03, // 3B, Block Status Register Mask
0x00, // 3C, "
0x50, // 3D, Vcc Logic Supply Optimum Program/Erase voltage
0x50, // 3E, Vpp [Programming] Supply Optimum Program/Erase voltage
0x00 // 3F, ??
};
//
// ROM buffer access functions
//
static __inline void WrDirtyPage(DWORD d)
{
if (pbyRomDirtyPage) // using dirty ROM page table
{
DWORD dwPage = d / ROMPAGESIZE; // this is the page
_ASSERT(dwPage < dwRomDirtyPageSize);
pbyRomDirtyPage[dwPage] = TRUE; // page is dirty
}
return;
}
static __inline void EraseBlock(DWORD d,DWORD dwNibSize)
{
LPBYTE pbyAddr = pbyRom + d;
while (dwNibSize--)
{
WrDirtyPage(d++); // make page dirty
*pbyAddr++ = 0x0F; // clear address
}
return;
}
static __inline void WriteByte(DWORD d,BYTE byData)
{
WrDirtyPage(d); // make page dirty
_ASSERT(d+1 < dwRomSize); // address valid?
*(pbyRom+d) &= (byData & 0x0F); // write LSB
*(pbyRom+d+1) &= (byData >> 4); // write MSB
return;
}
static __inline BYTE ReadByte(DWORD d)
{
_ASSERT(d+1 < dwRomSize); // address valid?
return *(pbyRom+d)|(*(pbyRom+d+1)<<4); // get byte
}
//
// write state functions
//
static VOID WrStateIdle(BYTE a, DWORD d)
{
WSMset.bRomArray = FALSE; // register access
switch(a)
{
case READ_ARRAY: // read array mode, normal operation
WSMset.bRomArray = TRUE; // data array access
WSMset.uWrState = WRS_DATA;
WSMset.uRdState = RDS_DATA;
break;
case READ_ID_CODES: // read identifier codes register
WSMset.uRdState = RDS_ID;
break;
case READ_QUERY: // read query register
WSMset.uRdState = RDS_QUERY;
break;
case READ_STATUS_REG: // read status register
WSMset.uRdState = RDS_SR;
break;
case CLEAR_STATUS_REG: // clear status register
WSMset.byStatusReg = 0;
break;
case WRITE_BUFFER: // write to buffer
WrStateE8(d);
break;
case WORD_BYTE_PROG1:
case WORD_BYTE_PROG2: // byte/word program
WrState40(d);
break;
case BLOCK_ERASE: // block erase
WrState20(d);
break;
case BLOCK_ERASE_SUSPEND: // block erase, word/byte program suspend
WSMset.byStatusReg |= WSMS; // operation suspended
WSMset.byStatusReg &= ~ESS; // block erase completed (because no timing emulation)
WSMset.byStatusReg &= ~BWSS; // program completed (because no timing emulation)
WSMset.uRdState = RDS_SR;
break;
case BLOCK_ERASE_RESUME: // block erase, word/byte program resume
WSMset.byStatusReg &= ~WSMS; // operation in progress
WSMset.byStatusReg &= ~ESS; // block erase in progress
WSMset.byStatusReg &= ~BWSS; // program in progress
WSMset.byStatusReg |= WSMS; // operation completed (because no timing emulation)
WSMset.uRdState = RDS_SR;
break;
case STS_CONFIG:
WSMset.bRomArray = bFlashRomArray; // old access mode
WrStateB8(d);
break;
case SET_CLR_BLOCK_LOCK: // set/clear block lock-bits
WrState60(d);
break;
case FULL_CHIP_ERASE: // full chip erase
WrState30(d);
break;
default: // wrong command
WSMset.bRomArray = bFlashRomArray; // old access mode
break;
}
if (bFlashRomArray != WSMset.bRomArray) // new access mode
{
bFlashRomArray = WSMset.bRomArray; // change register access
Map(0x00,0xFF); // update memory mapping
UpdatePatches(bFlashRomArray); // patch/unpatch ROM again
}
return;
}
// write to buffer initial command
static VOID WrStateE8(DWORD d)
{
// @todo add 2nd write buffer implementation
// @todo add program timing implementation
WSMset.byExStatusReg = 0; // no write buffer
if (WSMset.byWrite1No == 0) // buffer1 available
{
WSMset.byWrite1No = 1; // buffer1 in use
WSMset.dwWrite1Addr = d; // byte block address of buffer1
WSMset.byExStatusReg = WBS; // write buffer available
// fill write buffer
FillMemory(WSMset.pbyWrite1,ARRAYSIZEOF(WSMset.pbyWrite1),0xFF);
WSMset.uWrState = WRS_WR_BUFFER_N; // set state machine
WSMset.uRdState = RDS_XSR;
}
return;
}
// write to buffer number of byte
static VOID WrStateE8N(BYTE a, DWORD d)
{
if (a < (1 << byQueryTab[0x2A])) // byte is length information
{
WSMset.byWrite1No += a; // save no. of byte to program
WSMset.byWrite1Size = a; // save size to check write buffer boundaries
WSMset.dwWrite1Addr = d; // byte block address of buffer1
WSMset.byStatusReg &= ~WSMS; // state machine busy
WSMset.uWrState = WRS_WR_BUFFER_D;
}
else
{
WSMset.byWrite1No = 0; // free write buffer
// improper command sequence
WSMset.byStatusReg |= (ECLBS | BWSLBS);
WSMset.byStatusReg |= WSMS; // data written
WSMset.uWrState = WRS_DATA;
}
WSMset.uRdState = RDS_SR;
return;
}
// write to buffer data
static VOID WrStateE8D(BYTE a, DWORD d)
{
// first data byte
if (WSMset.byWrite1No == WSMset.byWrite1Size + 1)
{
DWORD dwBlockMask = ~(((byQueryTab[0x30] << 8) | byQueryTab[0x2F]) * 256 - 1);
// same block
if ((WSMset.dwWrite1Addr & dwBlockMask) == (d & dwBlockMask))
{
WSMset.dwWrite1Addr = d; // byte block address of buffer1
WSMset.pbyWrite1[0] = a; // save byte
}
else
{
WSMset.byWrite1No = 0; // free write buffer
// improper command sequence
WSMset.byStatusReg |= (ECLBS | BWSLBS);
WSMset.byStatusReg |= WSMS; // data written
WSMset.uWrState = WRS_DATA;
return;
}
}
else
{
// write address within buffer
if (d >= WSMset.dwWrite1Addr && d <= WSMset.dwWrite1Addr + WSMset.byWrite1Size)
{
// save byte in buffer
WSMset.pbyWrite1[d-WSMset.dwWrite1Addr] = a;
}
else
{
WSMset.byWrite1No = 0; // free write buffer
// improper command sequence
WSMset.byStatusReg |= (ECLBS | BWSLBS);
WSMset.byStatusReg |= WSMS; // data written
WSMset.uWrState = WRS_DATA;
return;
}
}
if (--WSMset.byWrite1No == 0) // last byte written
WSMset.uWrState = WRS_WR_BUFFER_C; // goto confirm state
return;
}
// write to buffer confirm
static VOID WrStateE8C(BYTE a, DWORD d)
{
if (CONFIRM == a) // write buffer confirm?
{
BYTE byPos;
d = WSMset.dwWrite1Addr << 1; // nibble start address
for (byPos = 0; byPos <= WSMset.byWrite1Size; ++byPos)
{
a = WSMset.pbyWrite1[byPos]; // get char from buffer
_ASSERT(d+1 < dwRomSize); // address valid?
// no error set in BWSLBS, because I could alway program a "0"
WriteByte(d,a); // write byte
d += 2; // next address
}
}
else
{
WSMset.byWrite1No = 0; // free write buffer
// improper command sequence
WSMset.byStatusReg |= (ECLBS | BWSLBS);
}
WSMset.byStatusReg |= WSMS; // data written
WSMset.uWrState = WRS_DATA;
return;
}
// byte/word program initial command
static VOID WrState40(DWORD d)
{
WSMset.byStatusReg &= ~WSMS; // state machine busy
WSMset.uWrState = WRS_WR_BYTE;
WSMset.uRdState = RDS_SR;
return;
UNREFERENCED_PARAMETER(d);
}
// byte/word program data
static VOID WrState40D(BYTE a, DWORD d)
{
// no error set in BWSLBS, because I could alway program a "0"
WriteByte(d << 1,a); // write byte
WSMset.byStatusReg |= WSMS; // data written
WSMset.uWrState = WRS_DATA;
return;
}
// block erase initial command
static VOID WrState20(DWORD d)
{
WSMset.byStatusReg &= ~WSMS; // state machine busy
WSMset.uWrState = WRS_BLOCK_ERASE;
WSMset.uRdState = RDS_SR;
return;
UNREFERENCED_PARAMETER(d);
}
// block erase data & confirm
static VOID WrState20C(BYTE a, DWORD d)
{
if (CONFIRM == a) // block erase confirm?
{
// lock bit of block is set
if ((WSMset.dwLockCnfg & (1<<(d>>16))) != 0)
{
WSMset.byStatusReg |= ECLBS; // error in block erasure
WSMset.byStatusReg |= DPS; // lock bit detected
}
else
{
DWORD dwBlockSize = ((byQueryTab[0x30] << 8) | byQueryTab[0x2F]) * 256;
d &= ~(dwBlockSize-1); // start of block
dwBlockSize *= 2; // block size in nibbles
_ASSERT(d+dwBlockSize <= dwRomSize); // address valid?
EraseBlock(d << 1,dwBlockSize); // erase 128K nibble
}
}
else
{
// improper command sequence
WSMset.byStatusReg |= (ECLBS | BWSLBS);
}
WSMset.byStatusReg |= WSMS; // block erased
WSMset.uWrState = WRS_DATA;
return;
}
// full chip erase initial command
static VOID WrState30(DWORD d)
{
WSMset.byStatusReg &= ~WSMS; // state machine busy
WSMset.uWrState = WRS_CHIP_ERASE;
WSMset.uRdState = RDS_SR;
return;
UNREFERENCED_PARAMETER(d);
}
// full chip erase confirm
static VOID WrState30C(BYTE a, DWORD d)
{
if (CONFIRM == a) // chip erase confirm?
{
UINT i;
WORD wNoOfBlocks = (byQueryTab[0x2E] << 8) | byQueryTab[0x2D];
DWORD dwBlockSize = ((byQueryTab[0x30] << 8) | byQueryTab[0x2F]) * 256;
DWORD dwBlockAddr = 0;
dwBlockSize *= 2; // block size in nibbles
for (i = 0; i <= wNoOfBlocks; ++i) // check all blocks
{
_ASSERT((i+1)*dwBlockSize <= dwRomSize);
// lock bit of block is set & WP# = low, locked blocks cannot be erased
if ((WSMset.dwLockCnfg & (1<<i)) == 0 || bWP != FALSE)
{
// clear block lock bit
WSMset.dwLockCnfg &= ~(1<<i);
// erase 128K nibble
EraseBlock(dwBlockAddr,dwBlockSize);
}
dwBlockAddr += dwBlockSize; // next block
}
}
else
{
// improper command sequence
WSMset.byStatusReg |= (ECLBS | BWSLBS);
}
WSMset.byStatusReg |= WSMS; // chip erased
WSMset.uWrState = WRS_DATA;
return;
UNREFERENCED_PARAMETER(d);
}
// STS pin Configuration initial command
static VOID WrStateB8(DWORD d)
{
WSMset.uWrState = WRS_STS_PIN_CONFIG;
return;
UNREFERENCED_PARAMETER(d);
}
// STS pin Configuration data
static VOID WrStateB8D(BYTE a, DWORD d)
{
// no emulation of STS pin Configuration
WSMset.uWrState = WRS_DATA;
return;
UNREFERENCED_PARAMETER(a);
UNREFERENCED_PARAMETER(d);
}
// Set/Clear block Lock-Bits initial command
static VOID WrState60(DWORD d)
{
WSMset.byStatusReg &= ~WSMS; // state machine busy
WSMset.uWrState = WRS_LOCK_BITS;
WSMset.uRdState = RDS_SR;
return;
UNREFERENCED_PARAMETER(d);
}
// Set/Clear block Lock-Bits confirm
static VOID WrState60D(BYTE a, DWORD d)
{
UINT i;
switch(a)
{
case 0x01: // set block lock bit
if (bWP) // WP# = high, can change block lock status
WSMset.dwLockCnfg |= (1<<(d>>16)); // set block lock bit
else
WSMset.byStatusReg |= (BWSLBS | DPS); // device protect detect, WP# = low
break;
case CONFIRM: // clear block lock bits
if (bWP) // WP# = high, can change block lock status
{
WORD wNoOfBlocks = (byQueryTab[0x2E] << 8) | byQueryTab[0x2D];
for (i = 0; i <= wNoOfBlocks; ++i) // clear all lock bits
{
WSMset.dwLockCnfg &= ~(1 << i); // clear block lock bit
}
}
else
{
WSMset.byStatusReg |= (ECLBS | DPS); // device protect detect, WP# = low
}
break;
default: // improper command sequence
WSMset.byStatusReg |= (ECLBS | BWSLBS);
}
WSMset.byStatusReg |= WSMS; // block lock-bit changed
WSMset.uWrState = WRS_DATA;
return;
}
//
// read state functions
//
// read array
static BYTE RdStateData(DWORD d)
{
return ReadByte(d << 1); // get byte
}
// read identifier codes
static BYTE RdStateId(DWORD d)
{
BYTE byData;
d >>= 1; // A0 is not connected, ignore it
if ((d & 0x03) != 0x02) // id code request
{
d &= 0x03; // data repetition
byData = byQueryTab[d]; // get data from first 4 bytes id/query table
}
else // block lock table
{
// get data from block lock table
byData = (BYTE) ((WSMset.dwLockCnfg >> (d >> 15)) & 1);
d &= 0x1F; // data repetition
if (d >= 4) byData |= 0x02; // set bit 1 on wrong ID adress
}
return byData;
}
// read query
static BYTE RdStateQuery(DWORD d)
{
BYTE byData;
d >>= 1; // A0 is not connected, ignore it
if ((d & 0x7F) != 0x02) // query request
{
d &= 0x7F; // data repetition
// get data from id/query table
byData = (d >= 0x40 && d < 0x50) ? 0 : byQueryTab[d&0x3F];
}
else // block lock table
{
// get data from block lock table
byData = (BYTE) ((WSMset.dwLockCnfg >> (d >> 15)) & 1);
}
return byData;
}
// read status register
static BYTE RdStateSR(DWORD d)
{
return WSMset.byStatusReg;
UNREFERENCED_PARAMETER(d);
}
// read extended status register
static BYTE RdStateXSR(DWORD d)
{
return WSMset.byExStatusReg;
UNREFERENCED_PARAMETER(d);
}
//
// public functions
//
VOID FlashInit(VOID)
{
// check if locking bit table has more or equal than 32 bit
_ASSERT(sizeof(WSMset.dwLockCnfg) * 8 >= 32);
ZeroMemory(&WSMset,sizeof(WSMset));
strcpy((LPSTR) WSMset.byType,"WSM"); // Write State Machine header
WSMset.uSize = sizeof(WSMset); // size of this structure
WSMset.byVersion = WSMVER; // version of flash implementation structure
// factory setting of locking bits
WSMset.dwLockCnfg = (1 << 0); // first 64KB block is locked
WSMset.uWrState = WRS_DATA;
WSMset.uRdState = RDS_DATA;
// data mode of ROM
WSMset.bRomArray = bFlashRomArray = TRUE;
return;
}
VOID FlashRead(BYTE *a, DWORD d, UINT s)
{
BYTE v;
while (s) // each nibble
{
// output muliplexer
_ASSERT(WSMset.uRdState < ARRAYSIZEOF(fnRdState));
v = fnRdState[WSMset.uRdState](d>>1);
if ((d & 1) == 0) // even address
{
*a++ = v & 0xf; ++d; --s;
}
if (s && (d & 1)) // odd address
{
*a++ = v >> 4; ++d; --s;
}
}
return;
}
VOID FlashWrite(BYTE *a, DWORD d, UINT s)
{
BYTE v;
DWORD p;
while (s) // each nibble
{
p = d >> 1; // byte address
if (s > 1 && (d & 1) == 0) // more than one byte on even address
{
v = *a++; // LSB
v |= *a++ << 4; // MSB
d += 2; s -= 2;
}
else
{
// get byte from output muliplexer
_ASSERT(WSMset.uRdState < ARRAYSIZEOF(fnRdState));
v = fnRdState[WSMset.uRdState](p);
if (d & 1) // odd address
v = (v & 0x0F) | (*a << 4); // replace MSB
else // even address
v = (v & 0xF0) | *a; // replace LSB
++a; ++d; --s;
}
_ASSERT(WSMset.uWrState < ARRAYSIZEOF(fnWrState));
fnWrState[WSMset.uWrState](v,p); // WSM
}
return;
}

View file

@ -0,0 +1,40 @@
/*
* i28f160.h
*
* This file is part of Emu48
*
* Copyright (C) 2000 Christoph Gießelink
*
*/
#define WSMVER 0 // version of flash implementation structure
#define WSMSET WSMset_t
typedef struct
{
BYTE byType[4]; // "WSM"
UINT uSize; // size of this structure
BYTE byVersion; // WSM version
BOOL bRomArray; // copy of bFlashRomArray
DWORD dwLockCnfg; // block lock table (32 entries)
UINT uWrState; // state of write function WSM
UINT uRdState; // state of read function WSM
BYTE byStatusReg; // status register
BYTE byExStatusReg; // extended status register
BYTE byWrite1No; // no. of written data in write buffer1
BYTE byWrite1Size; // no. of valid data in write buffer1
DWORD dwWrite1Addr; // destination address of buffer1
BYTE pbyWrite1[32]; // write buffer1
// BYTE byWrite2No; // no. of written data in write buffer2
// BYTE byWrite2Size; // no. of valid data in write buffer2
// DWORD dwWrite2Addr; // destination address of buffer2
// BYTE pbyWrite2[32]; // write buffer2
} WSMset_t;
// i28f160.h
extern WSMSET WSMset;
extern BOOL bWP;
extern VOID FlashInit(VOID);
extern VOID FlashRead(BYTE *a, DWORD d, UINT s);
extern VOID FlashWrite(BYTE *a, DWORD d, UINT s);

154
app/src/main/cpp/IO.H Normal file
View file

@ -0,0 +1,154 @@
/*
* io.h
*
* This file is part of Emu48
*
* Copyright (C) 1999 Christoph Gießelink
*
*/
// I/O addresses without mapping offset
#define BITOFFSET 0x00 // Display bit offset and DON
#define CRC 0x04 // Crc (16 bit, LSB first)
#define LPD 0x08 // Low Power Detection
#define LPE 0x09 // Low Power detection Enable
#define ANNCTRL 0x0b // Annunciator Control (2 nibble)
#define BAUD 0x0d // Baudrate (Bit 2-0)
#define CARDCTL 0x0e // card control
#define CARDSTAT 0x0f // card status
#define IOC 0x10 // IO CONTROL
#define RCS 0x11 // RCS
#define TCS 0x12 // TCS
#define CRER 0x13 // CRER
#define RBR_LSB 0x14 // RBR low nibble
#define RBR_MSB 0x15 // RBR high nibble
#define TBR_LSB 0x16 // TBR low nibble
#define TBR_MSB 0x17 // TBR high nibble
#define SRQ1 0x18 // SRQ1
#define SRQ2 0x19 // SRQ2
#define IR_CTRL 0x1a // IR CONTROL
#define LCR 0x1c // Led Control Register
#define LBR 0x1d // Led Buffer Register
#define DISP1CTL 0x20 // Display Start Address
#define LINENIBS 0x25 // Display Line Offset
#define LINECOUNT 0x28 // Display Line Counter
#define TIMER1_CTRL 0x2e // Timer1 Control
#define TIMER2_CTRL 0x2f // Timer2 Control
#define DISP2CTL 0x30 // Display Secondary Start Address
#define TIMER1 0x37 // Timer1 (4 bit)
#define TIMER2 0x38 // Timer2 (32 bit, LSB first)
// 0x00 Display bit offset and DON [DON OFF2 OFF1 OFF0]
#define DON 0x08 // Display On
#define OFF2 0x04 // Display OFFset Bit2
#define OFF1 0x02 // Display OFFset Bit1
#define OFF0 0x01 // Display OFFset Bit0
// 0x08 Low Power Detection [LB2 LB1 LB0 VLBI]
#define LB2 0x08 // Low Battery indicator memory port 2
#define LB1 0x04 // Low Battery indicator memory port 1
#define LB0 0x02 // Low Battery indicator system battery
#define VLBI 0x01 // Very Low Battery Indicator
// 0x09 Low Power detection Enable [ELBI EVLBI GRAM RST]
#define ELBI 0x08 // Enable Low Battery Indicator
#define EVLBI 0x04 // Enable Very Low Battery Indicator
#define GRAM 0x02 // Glitch sensitive RAM
#define RST 0x01 // ReSeT
// 0x0b Annunciator Control [AON XTRA LA6 LA5] [LA4 LA3 LA2 LA1]
#define AON 0x80 // Annunciators on
#define LXTRA 0x40 // does nothing
#define LA6 0x20 // LA6 - Transmitting
#define LA5 0x10 // LA5 - Busy
#define LA4 0x08 // LA4 - Alert
#define LA3 0x04 // LA3 - Alpha
#define LA2 0x02 // LA2 - ALT Shift
#define LA1 0x01 // LA1 - Shift
// 0x0d SERIAL Baud Rate [UCK BD2 BD1 BD0]
#define UCK 0x08 // Uart ClocK
#define BD2 0x04 // BauDrate Bit2
#define BD1 0x02 // BauDrate Bit1
#define BD0 0x01 // BauDrate Bit0
// 0x0e Card Control [ECDT RCDT SMP SWINT]
#define ECDT 0x08 // Enable Card Detect
#define RCDT 0x04 // Run Card Detect
#define SMP 0x02 // Set module pulled
#define SWINT 0x01 // Software Interrupt
// 0x0f Card Status [P2W P1W P2C P1C]
#define P2W 0x08 // High when Port2 writeable
#define P1W 0x04 // High when Port1 writeable
#define P2C 0x02 // High when Card in Port2 inserted
#define P1C 0x01 // High when Card in Port1 inserted
// 0x10 Serial I/O Control [SON ETBE ERBF ERBZ]
#define SON 0x08 // Serial on
#define ETBE 0x04 // Interrupt on transmit buffer empty
#define ERBF 0x02 // Interrupt on receive buffer full
#define ERBZ 0x01 // Interrupt on receiver busy
// 0x11 Serial Receive Control/Status [RX RER RBZ RBF]
#define RX 0x08 // Rx pin state (read-only)
#define RER 0x04 // Receiver error
#define RBZ 0x02 // Receiver busy
#define RBF 0x01 // Receive buffer full
// 0x12 Serial Transmit Control/Status [BRK LPB TBZ TBF]
#define BRK 0x08 // Break
#define LPB 0x04 // Loopback
#define TBZ 0x02 // Transmitter busy
#define TBF 0x01 // Transmit buffer full
// 0x18 Service Request Register 1 [ISRQ TSRQ USRQ VSRQ]
#define ISRQ 0x08 // IR receiver pulls NINT2
#define TSRQ 0x04 // Timer pulls NINT2
#define USRQ 0x02 // UART pulls NINT2
#define VSRQ 0x01 // VLBI pulls NINT2
// 0x19 Service Request Register 2 [KDN NINT2 NINT LSRQ]
#define KDN 0x08 // Bit set when ON Key or Key Interrupt
#define NINT2 0x04 // State of NINT2
#define NINT 0x02 // State of NINT
#define LSRQ 0x01 // LED driver pulls NINT2
// 0x1a IR Control Register [IRI EIRU EIRI IRE]
#define IRI 0x08 // IR input (read-only)
#define EIRU 0x04 // Enable IR UART mode
#define EIRI 0x02 // Enable IR interrupt
#define IRE 0x01 // IR event
// 0x1c Led Control Register [LED ELBE LBZ LBF]
#define LED 0x08 // Turn on LED
#define ELBE 0x04 // Enable Interrupt on Led Buffer empty
#define LBZ 0x02 // Led Port Busy
#define LBF 0x01 // Led Buffer Full
// 0x1d Led Buffer Register [0 0 0 LBO] (bits 1-3 read zero)
#define LBO 0x01
// 0x28 Display Line Counter LSB [LC3 LC2 LC1 LC0]
#define LC3 0x08 // LC3 - Line Counter Bit3
#define LC2 0x04 // LC2 - Line Counter Bit2
#define LC1 0x02 // LC1 - Line Counter Bit1
#define LC0 0x01 // LC0 - Line Counter Bit0
// 0x29 Display Line Counter MSB [DA19 M32 LC5 LC4]
#define DA19 0x08 // Drive A[19]
#define M32 0x04 // Multiplex 32 way
#define LC5 0x02 // LC5 - Line Counter Bit5
#define LC4 0x01 // LC4 - Line Counter Bit4
// 0x2e Timer1 Control [SRQ WKE INT XTRA]
#define SRQ 0x08 // Service request
#define WKE 0x04 // Wake up
#define INTR 0x02 // Interrupt
#define XTRA 0x01 // Extra function
// 0x2f Timer2 Control [SRQ WKE INT RUN]
#define SRQ 0x08 // Service request
#define WKE 0x04 // Wake up
#define INTR 0x02 // Interrupt
#define RUN 0x01 // Timer run

131
app/src/main/cpp/KEYBOARD.C Normal file
View file

@ -0,0 +1,131 @@
/*
* keyboard.c
*
* This file is part of Emu48
*
* Copyright (C) 1995 Sebastien Carlier
*
*/
#include "pch.h"
#include "Emu48.h"
#include "io.h" // I/O definitions
DWORD dwKeyMinDelay = 50; // minimum time for key hold
static WORD Keyboard_GetIR(VOID)
{
WORD r = 0;
// OR[0:8] are wired on Clarke/Yorke chip
if (Chipset.out==0) return 0;
if (Chipset.out&0x001) r|=Chipset.Keyboard_Row[0];
if (Chipset.out&0x002) r|=Chipset.Keyboard_Row[1];
if (Chipset.out&0x004) r|=Chipset.Keyboard_Row[2];
if (Chipset.out&0x008) r|=Chipset.Keyboard_Row[3];
if (Chipset.out&0x010) r|=Chipset.Keyboard_Row[4];
if (Chipset.out&0x020) r|=Chipset.Keyboard_Row[5];
if (Chipset.out&0x040) r|=Chipset.Keyboard_Row[6];
if (Chipset.out&0x080) r|=Chipset.Keyboard_Row[7];
if (Chipset.out&0x100) r|=Chipset.Keyboard_Row[8];
return r;
}
VOID ScanKeyboard(BOOL bActive, BOOL bReset)
{
// bActive = TRUE -> function called by direct read (A=IN, C=IN, RSI)
// FALSE -> function called by 1ms keyboard poll simulation
// bReset = TRUE -> Reset Chipset.in interrupt state register
// FALSE -> generate interrupt only for new pressed keys
// keyboard read not active?
if (!( bActive || Chipset.Shutdn || Chipset.IR15X
|| (Chipset.intk && (Chipset.IORam[TIMER2_CTRL]&RUN) != 0)))
{
EnterCriticalSection(&csKeyLock);
{
Chipset.in &= ~0x8000; // remove ON key
}
LeaveCriticalSection(&csKeyLock);
return;
}
EnterCriticalSection(&csKeyLock); // synchronize
{
BOOL bKbdInt;
WORD wOldIn = Chipset.in; // save old Chipset.in state
UpdateKdnBit(); // update KDN bit
Chipset.dwKdnCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
Chipset.in = Keyboard_GetIR(); // update Chipset.in register
Chipset.in |= Chipset.IR15X; // add ON key
// interrupt for any new pressed keys?
bKbdInt = (Chipset.in && (wOldIn & 0x1FF) == 0) || Chipset.IR15X || bReset;
// update keyboard interrupt pending flag when 1ms keyboard scan is disabled
Chipset.intd = Chipset.intd || (bKbdInt && !Chipset.intk);
// keyboard interrupt enabled?
bKbdInt = bKbdInt && Chipset.intk;
// interrupt at ON key pressed
bKbdInt = bKbdInt || Chipset.IR15X != 0;
// no interrupt if still inside interrupt service routine
bKbdInt = bKbdInt && Chipset.inte;
if (Chipset.in != 0) // any key pressed
{
if (bKbdInt) // interrupt enabled
{
Chipset.SoftInt = TRUE; // interrupt request
bInterrupt = TRUE; // exit emulation loop
}
if (Chipset.Shutdn) // cpu sleeping
{
Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode
SetEvent(hEventShutdn); // wake up emulation thread
}
}
else
{
Chipset.intd = FALSE; // no keyboard interrupt pending
}
}
LeaveCriticalSection(&csKeyLock);
return;
}
VOID KeyboardEvent(BOOL bPress, UINT out, UINT in)
{
if (nState != SM_RUN) // not in running state
return; // ignore key
KeyMacroRecord(bPress,out,in); // save all keyboard events
if (in == 0x8000) // ON key ?
{
Chipset.IR15X = bPress?0x8000:0x0000; // refresh special ON key flag
}
else
{
// "out" is outside Keyboard_Row
if (out >= ARRAYSIZEOF(Chipset.Keyboard_Row)) return;
// in &= 0x1FF; // only IR[0:8] are wired on Clarke/Yorke chip
_ASSERT(out < ARRAYSIZEOF(Chipset.Keyboard_Row));
if (bPress) // key pressed
Chipset.Keyboard_Row[out] |= in; // set key marker in keyboard row
else
Chipset.Keyboard_Row[out] &= (~in); // clear key marker in keyboard row
}
AdjKeySpeed(); // adjust key repeat speed
ScanKeyboard(FALSE,FALSE); // update Chipset.in register by 1ms keyboard poll
Sleep(dwKeyMinDelay); // hold key state for a definite time
return;
}

337
app/src/main/cpp/KEYMACRO.C Normal file
View file

@ -0,0 +1,337 @@
/*
* Keymacro.c
*
* This file is part of Emu48
*
* Copyright (C) 2004 Christoph Gießelink
*
*/
#include "pch.h"
#include "resource.h"
#include "Emu48.h"
#include "kml.h"
#define KEYMACROHEAD "Emu-KeyMacro" // macro signature
#define MIN_SPEED 0
#define MAX_SPEED 500
typedef struct
{
DWORD dwTime; // elapsed time
DWORD dwKeyEvent; // key code
} KeyData;
INT nMacroState = MACRO_OFF;
INT nMacroTimeout = MIN_SPEED;
BOOL bMacroRealSpeed = TRUE;
DWORD dwMacroMinDelay = 0; // minimum macro play key hold time in ms
static DWORD dwTimeRef;
static HANDLE hMacroFile = INVALID_HANDLE_VALUE;
static HANDLE hEventPlay = NULL;
static HANDLE hThreadEv = NULL;
static VOID InitializeOFN(LPOPENFILENAME ofn)
{
ZeroMemory((LPVOID)ofn, sizeof(OPENFILENAME));
ofn->lStructSize = sizeof(OPENFILENAME);
ofn->hwndOwner = hWnd;
ofn->Flags = OFN_EXPLORER|OFN_HIDEREADONLY;
return;
}
//
// thread playing keys
//
static DWORD WINAPI EventThread(LPVOID pParam)
{
DWORD dwRead = 0;
DWORD dwData = 0,dwTime = 0;
while (WaitForSingleObject(hEventPlay,dwTime) == WAIT_TIMEOUT)
{
if (dwRead != 0) // data read
{
UINT nIn = (dwData >> 0) & 0xFFFF;
UINT nOut = (dwData >> 16) & 0xFF;
BOOL bPress = (dwData >> 24) & 0xFF;
PlayKey(nOut,nIn,bPress);
}
dwTime = nMacroTimeout; // set default speed
while (TRUE)
{
// read next data element
if ( !ReadFile(hMacroFile,&dwData,sizeof(dwData),&dwRead,NULL)
|| dwRead != sizeof(dwData))
{
// play record empty -> quit
PostMessage(hWnd,WM_COMMAND,ID_TOOL_MACRO_STOP,0);
return 0; // exit on file end
}
if ((dwData & 0x80000000) != 0) // time information
{
if (bMacroRealSpeed) // realspeed from data
{
dwTime = dwData & 0x7FFFFFFF;
}
continue;
}
// hold the key state the minimum macro play key hold time
if (dwTime < dwMacroMinDelay) dwTime = dwMacroMinDelay;
dwTime -= dwKeyMinDelay; // remove the actual key hold time
// set negative number to zero
if ((dwTime & 0x80000000) != 0) dwTime = 0;
break; // got key information
}
}
return 0; // exit on stop
UNREFERENCED_PARAMETER(pParam);
}
//
// callback function for recording keys
//
VOID KeyMacroRecord(BOOL bPress, UINT out, UINT in)
{
if (nMacroState == MACRO_NEW) // save key event
{
KeyData Data;
DWORD dwWritten;
dwWritten = GetTickCount(); // time reference
Data.dwTime = (dwWritten - dwTimeRef);
Data.dwTime |= 0x80000000; // set time marker
dwTimeRef = dwWritten;
Data.dwKeyEvent = (bPress & 0xFF);
Data.dwKeyEvent = (Data.dwKeyEvent << 8) | (out & 0xFF);
Data.dwKeyEvent = (Data.dwKeyEvent << 16) | (in & 0xFFFF);
// save key event in file
WriteFile(hMacroFile,&Data,sizeof(Data),&dwWritten,NULL);
_ASSERT(dwWritten == sizeof(Data));
}
return;
}
//
// message handler for save new keyboard macro
//
LRESULT OnToolMacroNew(VOID)
{
TCHAR szMacroFile[MAX_PATH];
OPENFILENAME ofn;
DWORD dwExtensionLength,dwWritten;
// get filename for saving
InitializeOFN(&ofn);
ofn.lpstrFilter =
_T("Keyboard Macro Files (*.MAC)\0*.MAC\0")
_T("All Files (*.*)\0*.*\0");
ofn.lpstrDefExt = _T("MAC");
ofn.nFilterIndex = 1;
ofn.lpstrFile = szMacroFile;
ofn.lpstrFile[0] = 0;
ofn.nMaxFile = ARRAYSIZEOF(szMacroFile);
ofn.Flags |= OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT;
if (GetSaveFileName(&ofn) == FALSE) return 0;
// open file for writing
hMacroFile = CreateFile(szMacroFile,
GENERIC_READ|GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hMacroFile == INVALID_HANDLE_VALUE) return 0;
// write header
WriteFile(hMacroFile,KEYMACROHEAD,sizeof(KEYMACROHEAD) - 1,&dwWritten,NULL);
_ASSERT(dwWritten == (DWORD) strlen(KEYMACROHEAD));
// write extension length
dwExtensionLength = 0; // no extension
WriteFile(hMacroFile,&dwExtensionLength,sizeof(dwExtensionLength),&dwWritten,NULL);
_ASSERT(dwWritten == sizeof(dwExtensionLength));
nMacroState = MACRO_NEW;
MessageBox(hWnd,
_T("Press OK to begin to record the Macro."),
_T("Macro Recorder"),
MB_OK|MB_ICONINFORMATION);
dwTimeRef = GetTickCount(); // time reference
return 0;
}
//
// message handler for play keyboard macro
//
LRESULT OnToolMacroPlay(VOID)
{
BYTE byHeader[sizeof(KEYMACROHEAD)-1];
TCHAR szMacroFile[MAX_PATH];
OPENFILENAME ofn;
DWORD dwExtensionLength,dwRead,dwThreadId;
InitializeOFN(&ofn);
ofn.lpstrFilter =
_T("Keyboard Macro Files (*.MAC)\0*.MAC\0")
_T("All Files (*.*)\0*.*\0");
ofn.lpstrDefExt = _T("MAC");
ofn.nFilterIndex = 1;
ofn.lpstrFile = szMacroFile;
ofn.lpstrFile[0] = 0;
ofn.nMaxFile = ARRAYSIZEOF(szMacroFile);
ofn.Flags |= OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST;
if (GetOpenFileName(&ofn) == FALSE) return 0;
// open file for Reading
hMacroFile = CreateFile(szMacroFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hMacroFile == INVALID_HANDLE_VALUE) return 0;
// read header
ReadFile(hMacroFile,byHeader,sizeof(byHeader),&dwRead,NULL);
if ( dwRead != sizeof(byHeader)
|| memcmp(byHeader,KEYMACROHEAD,dwRead) != 0)
{
MessageBox(hWnd,
_T("Wrong keyboard macro file format."),
_T("Macro Recorder"),
MB_OK|MB_ICONSTOP);
CloseHandle(hMacroFile);
return 0;
}
// read extension length
ReadFile(hMacroFile,&dwExtensionLength,sizeof(dwExtensionLength),&dwRead,NULL);
if (dwRead != sizeof(dwExtensionLength))
{
CloseHandle(hMacroFile);
return 0;
}
// read extension
while (dwExtensionLength-- > 0)
{
BYTE byData;
ReadFile(hMacroFile,&byData,sizeof(byData),&dwRead,NULL);
if (dwRead != sizeof(byData))
{
CloseHandle(hMacroFile);
return 0;
}
}
// event for quit playing
hEventPlay = CreateEvent(NULL,FALSE,FALSE,NULL);
nMacroState = MACRO_PLAY;
// start playing thread
VERIFY(hThreadEv = CreateThread(NULL,0,&EventThread,NULL,0,&dwThreadId));
return 0;
}
//
// message handler for stop recording/playing
//
LRESULT OnToolMacroStop(VOID)
{
if (nMacroState != MACRO_OFF)
{
if (hEventPlay) // playing keys
{
// stop playing thread
SetEvent(hEventPlay); // quit play loop
WaitForSingleObject(hThreadEv,INFINITE);
CloseHandle(hThreadEv);
hThreadEv = NULL;
CloseHandle(hEventPlay); // close playing keys event
hEventPlay = NULL;
}
// macro file open
if (hMacroFile != INVALID_HANDLE_VALUE) CloseHandle(hMacroFile);
nMacroState = MACRO_OFF;
}
return 0;
}
//
// activate/deactivate slider
//
static VOID SliderEnable(HWND hDlg,BOOL bEnable)
{
EnableWindow(GetDlgItem(hDlg,IDC_MACRO_SLOW),bEnable);
EnableWindow(GetDlgItem(hDlg,IDC_MACRO_FAST),bEnable);
EnableWindow(GetDlgItem(hDlg,IDC_MACRO_SLIDER),bEnable);
return;
}
//
// Macro settings dialog
//
static INT_PTR CALLBACK MacroProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
// set slider
SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_SETRANGE,FALSE,MAKELONG(0,MAX_SPEED-MIN_SPEED));
SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_SETTICFREQ,MAX_SPEED/10,0);
SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_SETPOS,TRUE,MAX_SPEED-nMacroTimeout);
// set button
CheckDlgButton(hDlg,bMacroRealSpeed ? IDC_MACRO_REAL : IDC_MACRO_MANUAL,BST_CHECKED);
SliderEnable(hDlg,!bMacroRealSpeed);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_MACRO_REAL:
SliderEnable(hDlg,FALSE);
return TRUE;
case IDC_MACRO_MANUAL:
SliderEnable(hDlg,TRUE);
return TRUE;
case IDOK:
// get macro data
nMacroTimeout = MAX_SPEED - (INT) SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_GETPOS,0,0);
bMacroRealSpeed = IsDlgButtonChecked(hDlg,IDC_MACRO_REAL);
// no break
case IDCANCEL:
EndDialog(hDlg, LOWORD(wParam));
}
break;
}
return FALSE;
UNREFERENCED_PARAMETER(lParam);
}
LRESULT OnToolMacroSettings(VOID)
{
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_MACROSET), hWnd, (DLGPROC)MacroProc) == -1)
AbortMessage(_T("Macro Dialog Box Creation Error !"));
return 0;
}

2660
app/src/main/cpp/KML.C Normal file

File diff suppressed because it is too large Load diff

133
app/src/main/cpp/KML.H Normal file
View file

@ -0,0 +1,133 @@
/*
* kml.h
*
* This file is part of Emu48
*
* Copyright (C) 1995 Sebastien Carlier
*
*/
#define LEX_BLOCK 0
#define LEX_COMMAND 1
#define LEX_PARAM 2
typedef enum eTokenId
{
TOK_NONE, //0
TOK_ANNUNCIATOR, //1
TOK_BACKGROUND, //2
TOK_IFPRESSED, //3
TOK_RESETFLAG, //4
TOK_SCANCODE, //5
TOK_HARDWARE, //6
TOK_MENUITEM, //7
TOK_SYSITEM, //8
TOK_INTEGER, //9
TOK_SETFLAG, //10
TOK_RELEASE, //11
TOK_VIRTUAL, //12
TOK_INCLUDE, //13
TOK_NOTFLAG, //14
TOK_STRING, //15
TOK_GLOBAL, //16
TOK_AUTHOR, //17
TOK_BITMAP, //18
TOK_ZOOMXY, //19
TOK_OFFSET, //20
TOK_BUTTON, //21
TOK_IFFLAG, //22
TOK_ONDOWN, //23
TOK_NOHOLD, //24
TOK_LOCALE, //25
TOK_TOPBAR, //26
TOK_MENUBAR, //27
TOK_TITLE, //28
TOK_OUTIN, //29
TOK_PATCH, //30
TOK_PRINT, //31
TOK_DEBUG, //32
TOK_COLOR, //33
TOK_MODEL, //34
TOK_CLASS, //35
TOK_PRESS, //36
TOK_IFMEM, //37
TOK_SCALE, //38
TOK_TYPE, //39
TOK_SIZE, //40
TOK_DOWN, //41
TOK_ZOOM, //42
TOK_ELSE, //43
TOK_ONUP, //44
TOK_ICON, //45
TOK_EOL, //46
TOK_MAP, //47
TOK_ROM, //48
TOK_VGA, //49
TOK_LCD, //50
TOK_END //51
} TokenId;
#define TYPE_NONE 00
#define TYPE_INTEGER 01
#define TYPE_STRING 02
typedef struct KmlToken
{
TokenId eId;
DWORD nParams;
DWORD nLen;
LPCTSTR szName;
} KmlToken;
typedef struct KmlLine
{
struct KmlLine* pNext;
TokenId eCommand;
DWORD_PTR nParam[6];
} KmlLine;
typedef struct KmlBlock
{
TokenId eType;
DWORD nId;
struct KmlLine* pFirstLine;
struct KmlBlock* pNext;
} KmlBlock;
#define BUTTON_NOHOLD 0x0001
#define BUTTON_VIRTUAL 0x0002
typedef struct KmlButton
{
UINT nId;
BOOL bDown;
UINT nType;
DWORD dwFlags;
UINT nOx, nOy;
UINT nDx, nDy;
UINT nCx, nCy;
UINT nOut, nIn;
KmlLine* pOnDown;
KmlLine* pOnUp;
} KmlButton;
typedef struct KmlAnnunciator
{
UINT nOx, nOy;
UINT nDx, nDy;
UINT nCx, nCy;
} KmlAnnunciator;
extern KmlBlock* pKml;
extern BOOL DisplayChooseKml(CHAR cType);
extern VOID FreeBlocks(KmlBlock* pBlock);
extern VOID DrawAnnunciator(UINT nId, BOOL bOn);
extern VOID ReloadButtons(BYTE *Keyboard_Row, UINT nSize);
extern VOID RefreshButtons(RECT *rc);
extern BOOL MouseIsButton(DWORD x, DWORD y);
extern VOID MouseButtonDownAt(UINT nFlags, DWORD x, DWORD y);
extern VOID MouseButtonUpAt(UINT nFlags, DWORD x, DWORD y);
extern VOID MouseMovesTo(UINT nFlags, DWORD x, DWORD y);
extern VOID RunKey(BYTE nId, BOOL bPressed);
extern VOID PlayKey(UINT nOut, UINT nIn, BOOL bPressed);
extern BOOL InitKML(LPCTSTR szFilename, BOOL bNoLog);
extern VOID KillKML(VOID);

6300
app/src/main/cpp/LODEPNG.C Normal file

File diff suppressed because it is too large Load diff

1770
app/src/main/cpp/LODEPNG.H Normal file

File diff suppressed because it is too large Load diff

122
app/src/main/cpp/LOWBAT.C Normal file
View file

@ -0,0 +1,122 @@
/*
* lowbat.c
*
* This file is part of Emu48
*
* Copyright (C) 2006 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
#include "io.h" // I/O definitions
// #define BAT_SIMULATION // switch low bat simulation
#define BAT_FREQ (60*1000) // bat update time in ms (real machine = 60us, HP28C = 60s)
BOOL bLowBatDisable = FALSE;
static HANDLE hCThreadBat = NULL;
static HANDLE hEventBat;
static DWORD WINAPI LowBatThread(LPVOID pParam)
{
BOOL bLBI,bVLBI;
do
{
GetBatteryState(&bLBI,&bVLBI); // get battery state
// very low bat detection
bVLBI = bVLBI && (Chipset.IORam[LPE] & EVLBI) != 0;
IOBit(LPD,VLBI,bVLBI); // set VLBI
IOBit(SRQ1,VSRQ,bVLBI); // and service bit
if (bVLBI) // VLBI detected
{
Chipset.SoftInt = TRUE;
bInterrupt = TRUE;
if (Chipset.Shutdn) // CPU shut down
{
Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode
SetEvent(hEventShutdn); // wake up emulation thread
}
}
}
while (WaitForSingleObject(hEventBat,BAT_FREQ) == WAIT_TIMEOUT);
return 0;
UNREFERENCED_PARAMETER(pParam);
}
VOID StartBatMeasure(VOID)
{
DWORD dwThreadId;
if (hCThreadBat) // Bat measuring thread running
return; // -> quit
// event to cancel Bat refresh loop
hEventBat = CreateEvent(NULL,FALSE,FALSE,NULL);
VERIFY(hCThreadBat = CreateThread(NULL,0,&LowBatThread,NULL,0,&dwThreadId));
return;
}
VOID StopBatMeasure(VOID)
{
if (hCThreadBat == NULL) // thread stopped
return; // -> quit
SetEvent(hEventBat); // leave Bat update thread
WaitForSingleObject(hCThreadBat,INFINITE);
CloseHandle(hCThreadBat);
hCThreadBat = NULL; // set flag Bat update stopped
CloseHandle(hEventBat); // close Bat event
return;
}
VOID GetBatteryState(BOOL *pbLBI, BOOL *pbVLBI)
{
#if defined BAT_SIMULATION
switch (GetPrivateProfileInt(_T("LowBat"),_T("Level"),2,_T(".\\Lowbat.ini")))
{
case 0: // empty
*pbLBI = TRUE;
*pbVLBI = TRUE;
break;
case 1: // low
*pbLBI = TRUE;
*pbVLBI = FALSE;
break;
default: // full
*pbLBI = FALSE;
*pbVLBI = FALSE;
break;
}
#else
SYSTEM_POWER_STATUS sSps;
*pbLBI = FALSE; // no battery warning
*pbVLBI = FALSE;
VERIFY(GetSystemPowerStatus(&sSps));
// low bat emulation enabled and battery powered
if (!bLowBatDisable && sSps.ACLineStatus == AC_LINE_OFFLINE)
{
// on critical battery state make sure that lowbat flag is also set
if ((sSps.BatteryFlag & BATTERY_FLAG_CRITICAL) != 0)
sSps.BatteryFlag |= BATTERY_FLAG_LOW;
// low bat detection
*pbLBI = ((sSps.BatteryFlag & BATTERY_FLAG_LOW) != 0);
// very low bat detection
*pbVLBI = ((sSps.BatteryFlag & BATTERY_FLAG_CRITICAL) != 0);
}
#endif
return;
}

1851
app/src/main/cpp/MOPS.C Normal file

File diff suppressed because it is too large Load diff

353
app/src/main/cpp/MRU.C Normal file
View file

@ -0,0 +1,353 @@
/*
* mru.c
*
* This file is part of Emu48
*
* Copyright (C) 2007 Christoph Gießelink
*
*/
#include "pch.h"
#include "resource.h"
#include "Emu48.h"
static TCHAR szOriginal[MAX_PATH] = _T("");
static LPTSTR *ppszFiles = NULL; // pointer to MRU table
static UINT nEntry = 0; // no. of MRU entries
static BOOL GetMenuPosForId(HMENU hMenu, UINT nItem, HMENU *phMruMenu, UINT *pnMruPos)
{
HMENU hSubMenu;
UINT i,nID,nMaxID;
nMaxID = GetMenuItemCount(hMenu);
for (i = 0; i < nMaxID; ++i)
{
nID = GetMenuItemID(hMenu,i); // get ID
if (nID == 0) continue; // separator or invalid command
if (nID == (UINT)-1) // possibly a popup menu
{
hSubMenu = GetSubMenu(hMenu,i); // try to get handle to popup menu
if (hSubMenu != NULL) // it's a popup menu
{
// recursive search
if (GetMenuPosForId(hSubMenu,nItem,phMruMenu,pnMruPos))
return TRUE;
}
continue;
}
if (nID == nItem) // found ID
{
*phMruMenu = hMenu; // remember menu and position
*pnMruPos = i;
return TRUE;
}
}
return FALSE;
}
BOOL MruInit(UINT nNum)
{
HMENU hMenu = GetMenu(hWnd); // main menu
if (hMenu == NULL) return FALSE; // failed, no menu bar
_ASSERT(ppszFiles == NULL); // MRU already initialized
// no. of files in MRU list
nEntry = ReadSettingsInt(_T("MRU"),_T("FileCount"),nNum);
if (nEntry > 0) // allocate MRU table
{
// create MRU table
if ((ppszFiles = (LPTSTR *) malloc(nEntry * sizeof(*ppszFiles))) == NULL)
return FALSE;
// fill each entry
for (nNum = 0; nNum < nEntry; ++nNum)
ppszFiles[nNum] = NULL;
MruReadList(); // read actual MRU list
}
return TRUE;
}
VOID MruCleanup(VOID)
{
UINT i;
MruWriteList(); // write actual MRU list
if (ppszFiles != NULL) // table defined
{
for (i = 0; i < nEntry; ++i) // cleanup each entry
{
if (ppszFiles[i] != NULL)
free(ppszFiles[i]); // cleanup entry
}
free(ppszFiles); // free table
ppszFiles = NULL;
}
return;
}
VOID MruAdd(LPCTSTR lpszEntry)
{
TCHAR szFilename[MAX_PATH];
LPTSTR lpFilePart;
UINT i;
if (ppszFiles != NULL) // MRU initialized
{
_ASSERT(nEntry > 0); // must have entries
// get full path name
GetFullPathName(lpszEntry,ARRAYSIZEOF(szFilename),szFilename,&lpFilePart);
// look if entry is already in table
for (i = 0; i < nEntry; ++i)
{
// already in table -> quit
if ( ppszFiles[i] != NULL
&& lstrcmpi(ppszFiles[i],szFilename) == 0)
{
MruMoveTop(i); // move to top and update menu
return;
}
}
i = nEntry - 1; // last index
if (ppszFiles[i] != NULL)
free(ppszFiles[i]); // free oldest entry
for (; i > 0; --i) // move old entries 1 line down
{
ppszFiles[i] = ppszFiles[i-1];
}
// add new entry to top
ppszFiles[0] = DuplicateString(szFilename);
}
return;
}
VOID MruRemove(UINT nIndex)
{
// MRU initialized and index inside valid range
if (ppszFiles != NULL && nIndex < nEntry)
{
free(ppszFiles[nIndex]); // free entry
for (; nIndex < nEntry - 1; ++nIndex) // move below entries 1 line up
{
ppszFiles[nIndex] = ppszFiles[nIndex+1];
}
ppszFiles[nIndex] = NULL; // clear last line
}
return;
}
VOID MruMoveTop(UINT nIndex)
{
// MRU initialized and index inside valid range
if (ppszFiles != NULL && nIndex < nEntry)
{
LPTSTR lpszEntry = ppszFiles[nIndex];// remember selected entry
for (; nIndex > 0; --nIndex) // move above entries 1 line down
{
ppszFiles[nIndex] = ppszFiles[nIndex-1];
}
ppszFiles[0] = lpszEntry; // insert entry on top
}
return;
}
UINT MruEntries(VOID)
{
return nEntry;
}
LPCTSTR MruFilename(UINT nIndex)
{
LPCTSTR lpszName = _T("");
// MRU initialized and index inside valid range
if (ppszFiles != NULL && nIndex < nEntry)
{
lpszName = ppszFiles[nIndex];
}
return lpszName;
}
VOID MruUpdateMenu(HMENU hMenu)
{
TCHAR szCurPath[MAX_PATH];
BOOL bEmpty;
UINT i;
if (hMenu != NULL) // have menu
{
HMENU hMruMenu; // menu handle for MRU list
UINT nMruPos; // insert position for MRU list
_ASSERT(IsMenu(hMenu)); // validate menu handle
// search for menu position of ID_FILE_MRU_FILE1
if (GetMenuPosForId(hMenu,ID_FILE_MRU_FILE1,&hMruMenu,&nMruPos))
{
if (*szOriginal == 0) // get orginal value of first MRU entry
{
VERIFY(GetMenuString(hMruMenu,nMruPos,szOriginal,ARRAYSIZEOF(szOriginal),MF_BYPOSITION));
}
if (nEntry == 0) // kill MRU menu entry
{
// delete MRU menu
DeleteMenu(hMruMenu,nMruPos,MF_BYPOSITION);
// delete the following separator
_ASSERT((GetMenuState(hMruMenu,nMruPos,MF_BYPOSITION) & MF_SEPARATOR) != 0);
DeleteMenu(hMruMenu,nMruPos,MF_BYPOSITION);
}
if (ppszFiles != NULL) // MRU initialized
{
_ASSERT(nEntry > 0); // must have entries
// delete all menu entries
for (i = 0; DeleteMenu(hMenu,ID_FILE_MRU_FILE1+i,MF_BYCOMMAND) != FALSE; ++i) { }
// check if MRU list is empty
for (bEmpty = TRUE, i = 0; bEmpty && i < nEntry; ++i)
{
bEmpty = (ppszFiles[i] == NULL);
}
if (bEmpty) // MRU list is empty
{
// fill with orginal string
VERIFY(InsertMenu(hMruMenu,nMruPos,MF_STRING|MF_BYPOSITION|MF_GRAYED,ID_FILE_MRU_FILE1,szOriginal));
return;
}
// current directory
GetCurrentDirectory(ARRAYSIZEOF(szCurPath),szCurPath);
for (i = 0; i < nEntry; ++i) // add menu entries
{
if (ppszFiles[i] != NULL) // valid entry
{
TCHAR szMenuname[2*MAX_PATH+3];
TCHAR szFilename[MAX_PATH];
LPTSTR lpFilePart,lpszPtr;
// check if file path and current path is identical
if (GetFullPathName(ppszFiles[i],ARRAYSIZEOF(szFilename),szFilename,&lpFilePart))
{
TCHAR szCutname[MAX_PATH];
*(lpFilePart-1) = 0; // devide path and name
// name is current directory -> use only name
if (lstrcmpi(szCurPath,szFilename) == 0)
{
// short name view
}
else
{
// full name view
lpFilePart = ppszFiles[i];
}
// cut filename to fit into menu
GetCutPathName(lpFilePart,szCutname,ARRAYSIZEOF(szCutname),36);
lpFilePart = szCutname;
// adding accelerator key
lpszPtr = szMenuname;
*lpszPtr++ = _T('&');
*lpszPtr++ = _T('0') + ((i + 1) % 10);
*lpszPtr++ = _T(' ');
// copy file to view buffer and expand & to &&
while (*lpFilePart != 0)
{
if (*lpFilePart == _T('&'))
{
*lpszPtr++ = *lpFilePart;
}
*lpszPtr++ = *lpFilePart++;
}
*lpszPtr = 0;
VERIFY(InsertMenu(hMruMenu,nMruPos+i,
MF_STRING|MF_BYPOSITION,ID_FILE_MRU_FILE1+i,
szMenuname));
}
}
}
}
}
}
return;
}
VOID MruWriteList(VOID)
{
TCHAR szItemname[32];
UINT i;
if (nEntry > 0)
{
// no. of files in MRU list
WriteSettingsInt(_T("MRU"),_T("FileCount"),nEntry);
for (i = 0; i < nEntry; ++i) // add menu entries
{
_ASSERT(ppszFiles != NULL); // MRU not initialized
wsprintf(szItemname,_T("File%d"),i+1);
if (ppszFiles[i] != NULL)
{
WriteSettingsString(_T("MRU"),szItemname,ppszFiles[i]);
}
else
{
DelSettingsKey(_T("MRU"),szItemname);
}
}
}
return;
}
VOID MruReadList(VOID)
{
TCHAR szFilename[MAX_PATH];
TCHAR szItemname[32];
UINT i;
for (i = 0; i < nEntry; ++i) // add menu entries
{
_ASSERT(ppszFiles != NULL); // MRU not initialized
wsprintf(szItemname,_T("File%d"),i+1);
ReadSettingsString(_T("MRU"),szItemname,_T(""),szFilename,ARRAYSIZEOF(szFilename));
if (ppszFiles[i] != NULL) // already filled
{
free(ppszFiles[i]); // free entry
ppszFiles[i] = NULL; // clear last line
}
if (*szFilename) // read a valid entry
{
ppszFiles[i] = DuplicateString(szFilename);
}
}
return;
}

2463
app/src/main/cpp/OPCODES.C Normal file

File diff suppressed because it is too large Load diff

445
app/src/main/cpp/OPCODES.H Normal file
View file

@ -0,0 +1,445 @@
/*
* opcodes.h
*
* This file is part of Emu48
*
* Copyright (C) 1999 Christoph Gießelink
*
*/
#define PCHANGED ((void)(F_s[0]=Chipset.P,F_l[1]=Chipset.P+1))
#define INTERRUPT ((void)(Chipset.SoftInt=TRUE,bInterrupt=TRUE))
extern UINT F_s[16];
extern UINT F_l[16];
extern VOID o00(LPBYTE I); // RTNSXM
extern VOID o01(LPBYTE I); // RTN
extern VOID o02(LPBYTE I); // RTNSC
extern VOID o03(LPBYTE I); // RTNCC
extern VOID o04(LPBYTE I); // SETHEX
extern VOID o05(LPBYTE I); // SETDEC
extern VOID o06(LPBYTE I); // RSTK=C
extern VOID o07(LPBYTE I); // C=RSTK
extern VOID o08(LPBYTE I); // CLRST
extern VOID o09(LPBYTE I); // C=ST
extern VOID o0A(LPBYTE I); // ST=C
extern VOID o0B(LPBYTE I); // CSTEX
extern VOID o0C(LPBYTE I); // P=P+1
extern VOID o0D(LPBYTE I); // P=P-1
extern VOID o0Ef0(LPBYTE I); // A=A&B f
extern VOID o0Ef1(LPBYTE I); // B=B&C f
extern VOID o0Ef2(LPBYTE I); // C=C&A f
extern VOID o0Ef3(LPBYTE I); // D=D&C f
extern VOID o0Ef4(LPBYTE I); // B=B&A f
extern VOID o0Ef5(LPBYTE I); // C=C&B f
extern VOID o0Ef6(LPBYTE I); // A=A&C f
extern VOID o0Ef7(LPBYTE I); // C=C&D f
extern VOID o0Ef8(LPBYTE I); // A=A!B f
extern VOID o0Ef9(LPBYTE I); // B=B!C f
extern VOID o0EfA(LPBYTE I); // C=C!A f
extern VOID o0EfB(LPBYTE I); // D=D!C f
extern VOID o0EfC(LPBYTE I); // B=B!A f
extern VOID o0EfD(LPBYTE I); // C=C!B f
extern VOID o0EfE(LPBYTE I); // A=A!C f
extern VOID o0EfF(LPBYTE I); // C=C!D f
extern VOID o0F(LPBYTE I); // RTI
extern VOID o100(LPBYTE I); // R0=A W
extern VOID o101(LPBYTE I); // R1=A W
extern VOID o102(LPBYTE I); // R2=A W
extern VOID o103(LPBYTE I); // R3=A W
extern VOID o104(LPBYTE I); // R4=A W
extern VOID o108(LPBYTE I); // R0=C W
extern VOID o109(LPBYTE I); // R1=C W
extern VOID o10A(LPBYTE I); // R2=C W
extern VOID o10B(LPBYTE I); // R3=C W
extern VOID o10C(LPBYTE I); // R4=C W
extern VOID o110(LPBYTE I); // A=R0 W
extern VOID o111(LPBYTE I); // A=R1 W
extern VOID o112(LPBYTE I); // A=R2 W
extern VOID o113(LPBYTE I); // A=R3 W
extern VOID o114(LPBYTE I); // A=R4 W
extern VOID o118(LPBYTE I); // C=R0 W
extern VOID o119(LPBYTE I); // C=R1 W
extern VOID o11A(LPBYTE I); // C=R2 W
extern VOID o11B(LPBYTE I); // C=R3 W
extern VOID o11C(LPBYTE I); // C=R4 W
extern VOID o120(LPBYTE I); // AR0EX W
extern VOID o121(LPBYTE I); // AR1EX W
extern VOID o122(LPBYTE I); // AR2EX W
extern VOID o123(LPBYTE I); // AR3EX W
extern VOID o124(LPBYTE I); // AR4EX W
extern VOID o128(LPBYTE I); // CR0EX W
extern VOID o129(LPBYTE I); // CR1EX W
extern VOID o12A(LPBYTE I); // CR2EX W
extern VOID o12B(LPBYTE I); // CR3EX W
extern VOID o12C(LPBYTE I); // CR4EX W
extern VOID o130(LPBYTE I); // D0=A
extern VOID o131(LPBYTE I); // D1=A
extern VOID o132(LPBYTE I); // AD0EX
extern VOID o133(LPBYTE I); // AD1EX
extern VOID o134(LPBYTE I); // D0=C
extern VOID o135(LPBYTE I); // D1=C
extern VOID o136(LPBYTE I); // CD0EX
extern VOID o137(LPBYTE I); // CD1EX
extern VOID o138(LPBYTE I); // D0=AS
extern VOID o139(LPBYTE I); // D1=AS
extern VOID o13A(LPBYTE I); // AD0XS
extern VOID o13B(LPBYTE I); // AD1XS
extern VOID o13C(LPBYTE I); // D0=CS
extern VOID o13D(LPBYTE I); // D1=CS
extern VOID o13E(LPBYTE I); // CD0XS
extern VOID o13F(LPBYTE I); // CD1XS
extern VOID o140(LPBYTE I); // DAT0=A A
extern VOID o141(LPBYTE I); // DAT0=A A
extern VOID o144(LPBYTE I); // DAT0=C A
extern VOID o145(LPBYTE I); // DAT1=C A
extern VOID o148(LPBYTE I); // DAT0=A B
extern VOID o149(LPBYTE I); // DAT1=A B
extern VOID o14C(LPBYTE I); // DAT0=C B
extern VOID o14D(LPBYTE I); // DAT1=C B
extern VOID o142(LPBYTE I); // A=DAT0 A
extern VOID o143(LPBYTE I); // A=DAT1 A
extern VOID o146(LPBYTE I); // C=DAT0 A
extern VOID o147(LPBYTE I); // C=DAT1 A
extern VOID o14A(LPBYTE I); // A=DAT0 B
extern VOID o14B(LPBYTE I); // A=DAT1 B
extern VOID o14E(LPBYTE I); // C=DAT0 B
extern VOID o14F(LPBYTE I); // C=DAT0 B
extern VOID o150a(LPBYTE I); // DAT0=A a
extern VOID o151a(LPBYTE I); // DAT1=A a
extern VOID o154a(LPBYTE I); // DAT0=C a
extern VOID o155a(LPBYTE I); // DAT1=C a
extern VOID o152a(LPBYTE I); // A=DAT0 a
extern VOID o153a(LPBYTE I); // A=DAT1 a
extern VOID o156a(LPBYTE I); // C=DAT0 a
extern VOID o157a(LPBYTE I); // C=DAT1 a
extern VOID o158x(LPBYTE I); // DAT0=A x
extern VOID o159x(LPBYTE I); // DAT1=A x
extern VOID o15Cx(LPBYTE I); // DAT0=C x
extern VOID o15Dx(LPBYTE I); // DAT1=C x
extern VOID o15Ax(LPBYTE I); // A=DAT0 x
extern VOID o15Bx(LPBYTE I); // A=DAT1 x
extern VOID o15Ex(LPBYTE I); // C=DAT0 x
extern VOID o15Fx(LPBYTE I); // C=DAT1 x
extern VOID o16x(LPBYTE I); // D0=D0+ (n+1)
extern VOID o17x(LPBYTE I); // D1=D1+ (n+1)
extern VOID o18x(LPBYTE I); // D0=D0- (n+1)
extern VOID o19d2(LPBYTE I); // D0=(2) #dd
extern VOID o1Ad4(LPBYTE I); // D0=(4) #dddd
extern VOID o1Bd5(LPBYTE I); // D0=(5) #ddddd
extern VOID o1Cx(LPBYTE I); // D1=D1- (n+1)
extern VOID o1Dd2(LPBYTE I); // D1=(2) #dd
extern VOID o1Ed4(LPBYTE I); // D1=(4) #dddd
extern VOID o1Fd5(LPBYTE I); // D1=(5) #ddddd
extern VOID o2n(LPBYTE I); // P= n
extern VOID o3X(LPBYTE I); // LCHEX
extern VOID o4d2(LPBYTE I); // GOC #dd
extern VOID o5d2(LPBYTE I); // GONC
extern VOID o6d3(LPBYTE I); // GOTO
extern VOID o7d3(LPBYTE I); // GOSUB
extern VOID o800(LPBYTE I); // OUT=CS
extern VOID o801(LPBYTE I); // OUT=C
extern VOID o802(LPBYTE I); // A=IN
extern VOID o803(LPBYTE I); // C=IN
extern VOID o804(LPBYTE I); // UNCNFG
extern VOID o805(LPBYTE I); // CONFIG
extern VOID o806(LPBYTE I); // C=ID
extern VOID o807(LPBYTE I); // SHUTDN
extern VOID o8080(LPBYTE I); // INTON
extern VOID o80810(LPBYTE I); // RSI
extern VOID o8082X(LPBYTE I); // LA
extern VOID o8083(LPBYTE I); // BUSCB
extern VOID o8084n(LPBYTE I); // ABIT=0 n
extern VOID o8085n(LPBYTE I); // ABIT=1 n
extern VOID o8086n(LPBYTE I); // ?ABIT=0 n
extern VOID o8087n(LPBYTE I); // ?ABIT=1 n
extern VOID o8088n(LPBYTE I); // CBIT=0 n
extern VOID o8089n(LPBYTE I); // CBIT=1 n
extern VOID o808An(LPBYTE I); // ?CBIT=0 n
extern VOID o808Bn(LPBYTE I); // ?CBIT=1 n
extern VOID o808C(LPBYTE I); // PC=(A)
extern VOID o808D(LPBYTE I); // BUSCD
extern VOID o808E(LPBYTE I); // PC=(C)
extern VOID o808F(LPBYTE I); // INTOFF
extern VOID o809(LPBYTE I); // C+P+1 - HEX MODE
extern VOID o80A(LPBYTE I); // RESET
extern VOID o80B(LPBYTE I); // BUSCC
extern VOID o80Cn(LPBYTE I); // C=P n
extern VOID o80Dn(LPBYTE I); // P=C n
extern VOID o80E(LPBYTE I); // SREQ?
extern VOID o80Fn(LPBYTE I); // CPEX n
extern VOID o810(LPBYTE I); // ASLC
extern VOID o811(LPBYTE I); // BSLC
extern VOID o812(LPBYTE I); // CSLC
extern VOID o813(LPBYTE I); // DSLC
extern VOID o814(LPBYTE I); // ASRC
extern VOID o815(LPBYTE I); // BSRC
extern VOID o816(LPBYTE I); // CSRC
extern VOID o817(LPBYTE I); // DSRC
extern VOID o818f0x(LPBYTE I); // A=A+x+1 f
extern VOID o818f1x(LPBYTE I); // B=B+x+1 f
extern VOID o818f2x(LPBYTE I); // C=C+x+1 f
extern VOID o818f3x(LPBYTE I); // D=D+x+1 f
extern VOID o818f8x(LPBYTE I); // A=A-x-1 f
extern VOID o818f9x(LPBYTE I); // B=B-x-1 f
extern VOID o818fAx(LPBYTE I); // C=C-x-1 f
extern VOID o818fBx(LPBYTE I); // D=D-x-1 f
extern VOID o819f0(LPBYTE I); // ASRB.F
extern VOID o819f1(LPBYTE I); // BSRB.F
extern VOID o819f2(LPBYTE I); // CSRB.F
extern VOID o819f3(LPBYTE I); // DSRB.F
extern VOID o81Af00(LPBYTE I); // R0=A.F f
extern VOID o81Af01(LPBYTE I); // R1=A.F f
extern VOID o81Af02(LPBYTE I); // R2=A.F f
extern VOID o81Af03(LPBYTE I); // R3=A.F f
extern VOID o81Af04(LPBYTE I); // R4=A.F f
extern VOID o81Af08(LPBYTE I); // R0=C.F f
extern VOID o81Af09(LPBYTE I); // R1=C.F f
extern VOID o81Af0A(LPBYTE I); // R2=C.F f
extern VOID o81Af0B(LPBYTE I); // R3=C.F f
extern VOID o81Af0C(LPBYTE I); // R4=C.F f
extern VOID o81Af10(LPBYTE I); // A=R0.F f
extern VOID o81Af11(LPBYTE I); // A=R1.F f
extern VOID o81Af12(LPBYTE I); // A=R2.F f
extern VOID o81Af13(LPBYTE I); // A=R3.F f
extern VOID o81Af14(LPBYTE I); // A=R4.F f
extern VOID o81Af18(LPBYTE I); // C=R0.F f
extern VOID o81Af19(LPBYTE I); // C=R1.F f
extern VOID o81Af1A(LPBYTE I); // C=R2.F f
extern VOID o81Af1B(LPBYTE I); // C=R3.F f
extern VOID o81Af1C(LPBYTE I); // C=R4.F f
extern VOID o81Af20(LPBYTE I); // AR0EX.F f
extern VOID o81Af21(LPBYTE I); // AR1EX.F f
extern VOID o81Af22(LPBYTE I); // AR2EX.F f
extern VOID o81Af23(LPBYTE I); // AR3EX.F f
extern VOID o81Af24(LPBYTE I); // AR4EX.F f
extern VOID o81Af28(LPBYTE I); // CR0EX.F f
extern VOID o81Af29(LPBYTE I); // CR1EX.F f
extern VOID o81Af2A(LPBYTE I); // CR2EX.F f
extern VOID o81Af2B(LPBYTE I); // CR3EX.F f
extern VOID o81Af2C(LPBYTE I); // CR4EX.F f
extern VOID o81B2(LPBYTE I); // PC=A
extern VOID o81B3(LPBYTE I); // PC=C
extern VOID o81B4(LPBYTE I); // A=PC
extern VOID o81B5(LPBYTE I); // C=PC
extern VOID o81B6(LPBYTE I); // APCEX
extern VOID o81B7(LPBYTE I); // CPCEX
extern VOID o81C(LPBYTE I); // ASRB
extern VOID o81D(LPBYTE I); // BSRB
extern VOID o81E(LPBYTE I); // CSRB
extern VOID o81F(LPBYTE I); // DSRB
extern VOID o82n(LPBYTE I); // HST=0 m
extern VOID o83n(LPBYTE I); // ?HST=0 m
extern VOID o84n(LPBYTE I); // ST=0 n
extern VOID o85n(LPBYTE I); // ST=1 n
extern VOID o86n(LPBYTE I); // ?ST=0 n
extern VOID o87n(LPBYTE I); // ?ST=1 n
extern VOID o88n(LPBYTE I); // ?P# n
extern VOID o89n(LPBYTE I); // ?P= n
extern VOID o8A0(LPBYTE I); // ?A=B A
extern VOID o8A1(LPBYTE I); // ?B=C A
extern VOID o8A2(LPBYTE I); // ?C=A A
extern VOID o8A3(LPBYTE I); // ?D=C A
extern VOID o8A4(LPBYTE I); // ?A#B A
extern VOID o8A5(LPBYTE I); // ?B#C A
extern VOID o8A6(LPBYTE I); // ?C#A A
extern VOID o8A7(LPBYTE I); // ?D#C A
extern VOID o8A8(LPBYTE I); // ?A=0 A
extern VOID o8A9(LPBYTE I); // ?B=0 A
extern VOID o8AA(LPBYTE I); // ?C=0 A
extern VOID o8AB(LPBYTE I); // ?D=0 A
extern VOID o8AC(LPBYTE I); // ?A#0 A
extern VOID o8AD(LPBYTE I); // ?B#0 A
extern VOID o8AE(LPBYTE I); // ?C#0 A
extern VOID o8AF(LPBYTE I); // ?D#0 A
extern VOID o8B0(LPBYTE I); // ?A>B A
extern VOID o8B1(LPBYTE I); // ?B>C A
extern VOID o8B2(LPBYTE I); // ?C>A A
extern VOID o8B3(LPBYTE I); // ?D>C A
extern VOID o8B4(LPBYTE I); // ?A<B A
extern VOID o8B5(LPBYTE I); // ?B<C A
extern VOID o8B6(LPBYTE I); // ?C<A A
extern VOID o8B7(LPBYTE I); // ?D<C A
extern VOID o8B8(LPBYTE I); // ?A>=B A
extern VOID o8B9(LPBYTE I); // ?B>=C A
extern VOID o8BA(LPBYTE I); // ?C>=A A
extern VOID o8BB(LPBYTE I); // ?D>=C A
extern VOID o8BC(LPBYTE I); // ?A<=B A
extern VOID o8BD(LPBYTE I); // ?B<=C A
extern VOID o8BE(LPBYTE I); // ?C<=A A
extern VOID o8BF(LPBYTE I); // ?D<=C A
extern VOID o8Cd4(LPBYTE I); // GOLONG #dddd
extern VOID o8Dd5(LPBYTE I); // GOVLNG #ddddd
extern VOID o8Ed4(LPBYTE I); // GOSUBL #dddd
extern VOID o8Fd5(LPBYTE I); // GOSBVL #ddddd
extern VOID o9a0(LPBYTE I); // ?A=B f
extern VOID o9a1(LPBYTE I); // ?B=C f
extern VOID o9a2(LPBYTE I); // ?C=A f
extern VOID o9a3(LPBYTE I); // ?D=C f
extern VOID o9a4(LPBYTE I); // ?A#B f
extern VOID o9a5(LPBYTE I); // ?B#C f
extern VOID o9a6(LPBYTE I); // ?C#A f
extern VOID o9a7(LPBYTE I); // ?D#C f
extern VOID o9a8(LPBYTE I); // ?A=0 f
extern VOID o9a9(LPBYTE I); // ?B=0 f
extern VOID o9aA(LPBYTE I); // ?C=0 f
extern VOID o9aB(LPBYTE I); // ?D=0 f
extern VOID o9aC(LPBYTE I); // ?A#0 f
extern VOID o9aD(LPBYTE I); // ?B#0 f
extern VOID o9aE(LPBYTE I); // ?C#0 f
extern VOID o9aF(LPBYTE I); // ?D#0 f
extern VOID o9b0(LPBYTE I); // ?A>B f
extern VOID o9b1(LPBYTE I); // ?B>C f
extern VOID o9b2(LPBYTE I); // ?C>A f
extern VOID o9b3(LPBYTE I); // ?D>C f
extern VOID o9b4(LPBYTE I); // ?A<B f
extern VOID o9b5(LPBYTE I); // ?B<C f
extern VOID o9b6(LPBYTE I); // ?C<A f
extern VOID o9b7(LPBYTE I); // ?D<C f
extern VOID o9b8(LPBYTE I); // ?A>=B f
extern VOID o9b9(LPBYTE I); // ?B>=C f
extern VOID o9bA(LPBYTE I); // ?C>=A f
extern VOID o9bB(LPBYTE I); // ?D>=C f
extern VOID o9bC(LPBYTE I); // ?A<=B f
extern VOID o9bD(LPBYTE I); // ?B<=C f
extern VOID o9bE(LPBYTE I); // ?C<=A f
extern VOID o9bF(LPBYTE I); // ?D<=C f
extern VOID oAa0(LPBYTE I); // A=A+B f
extern VOID oAa1(LPBYTE I); // B=B+C f
extern VOID oAa2(LPBYTE I); // C=C+A f
extern VOID oAa3(LPBYTE I); // D=D+C f
extern VOID oAa4(LPBYTE I); // A=A+A f
extern VOID oAa5(LPBYTE I); // B=B+B f
extern VOID oAa6(LPBYTE I); // C=C+C f
extern VOID oAa7(LPBYTE I); // D=D+D f
extern VOID oAa8(LPBYTE I); // B=B+A f
extern VOID oAa9(LPBYTE I); // C=C+B f
extern VOID oAaA(LPBYTE I); // A=A+C f
extern VOID oAaB(LPBYTE I); // C=C+D f
extern VOID oAaC(LPBYTE I); // A=A-1 f
extern VOID oAaD(LPBYTE I); // B=B-1 f
extern VOID oAaE(LPBYTE I); // C=C-1 f
extern VOID oAaF(LPBYTE I); // D=D-1 f
extern VOID oAb0(LPBYTE I); // A=0 f
extern VOID oAb1(LPBYTE I); // B=0 f
extern VOID oAb2(LPBYTE I); // C=0 f
extern VOID oAb3(LPBYTE I); // D=0 f
extern VOID oAb4(LPBYTE I); // A=B f
extern VOID oAb5(LPBYTE I); // B=C f
extern VOID oAb6(LPBYTE I); // C=A f
extern VOID oAb7(LPBYTE I); // D=C f
extern VOID oAb8(LPBYTE I); // B=A f
extern VOID oAb9(LPBYTE I); // C=B f
extern VOID oAbA(LPBYTE I); // A=C f
extern VOID oAbB(LPBYTE I); // C=D f
extern VOID oAbC(LPBYTE I); // ABEX f
extern VOID oAbD(LPBYTE I); // BCEX f
extern VOID oAbE(LPBYTE I); // CAEX f
extern VOID oAbF(LPBYTE I); // DCEX f
extern VOID oBa0(LPBYTE I); // A=A-B f
extern VOID oBa1(LPBYTE I); // B=B-C f
extern VOID oBa2(LPBYTE I); // C=C-A f
extern VOID oBa3(LPBYTE I); // D=D-C f
extern VOID oBa4(LPBYTE I); // A=A+1 f
extern VOID oBa5(LPBYTE I); // B=B+1 f
extern VOID oBa6(LPBYTE I); // C=C+1 f
extern VOID oBa7(LPBYTE I); // D=D+1 f
extern VOID oBa8(LPBYTE I); // B=B-A f
extern VOID oBa9(LPBYTE I); // C=C-B f
extern VOID oBaA(LPBYTE I); // A=A-C f
extern VOID oBaB(LPBYTE I); // C=C-D f
extern VOID oBaC(LPBYTE I); // A=B-A f
extern VOID oBaD(LPBYTE I); // B=C-B f
extern VOID oBaE(LPBYTE I); // C=A-C f
extern VOID oBaF(LPBYTE I); // D=C-D f
extern VOID oBb0(LPBYTE I); // ASL f
extern VOID oBb1(LPBYTE I); // BSL f
extern VOID oBb2(LPBYTE I); // CSL f
extern VOID oBb3(LPBYTE I); // DSL f
extern VOID oBb4(LPBYTE I); // ASR f
extern VOID oBb5(LPBYTE I); // BSR f
extern VOID oBb6(LPBYTE I); // CSR f
extern VOID oBb7(LPBYTE I); // DSR f
extern VOID oBb8(LPBYTE I); // A=-A f
extern VOID oBb9(LPBYTE I); // B=-B f
extern VOID oBbA(LPBYTE I); // C=-C f
extern VOID oBbB(LPBYTE I); // D=-D f
extern VOID oBbC(LPBYTE I); // A=-A-1 f
extern VOID oBbD(LPBYTE I); // B=-B-1 f
extern VOID oBbE(LPBYTE I); // C=-C-1 f
extern VOID oBbF(LPBYTE I); // D=-D-1 f
extern VOID oC0(LPBYTE I); // A=A+B A
extern VOID oC1(LPBYTE I); // B=B+C A
extern VOID oC2(LPBYTE I); // C=C+A A
extern VOID oC3(LPBYTE I); // D=D+C A
extern VOID oC4(LPBYTE I); // A=A+A A
extern VOID oC5(LPBYTE I); // B=B+B A
extern VOID oC6(LPBYTE I); // C=C+C A
extern VOID oC7(LPBYTE I); // D=D+D A
extern VOID oC8(LPBYTE I); // B=B+A A
extern VOID oC9(LPBYTE I); // C=C+B A
extern VOID oCA(LPBYTE I); // A=A+C A
extern VOID oCB(LPBYTE I); // C=C+D A
extern VOID oCC(LPBYTE I); // A=A-1 A
extern VOID oCD(LPBYTE I); // B=B-1 A
extern VOID oCE(LPBYTE I); // C=C-1 A
extern VOID oCF(LPBYTE I); // D=D-1 A
extern VOID oD0(LPBYTE I); // A=0 A
extern VOID oD1(LPBYTE I); // B=0 A
extern VOID oD2(LPBYTE I); // C=0 A
extern VOID oD3(LPBYTE I); // D=0 A
extern VOID oD4(LPBYTE I); // A=B A
extern VOID oD5(LPBYTE I); // B=C A
extern VOID oD6(LPBYTE I); // C=A A
extern VOID oD7(LPBYTE I); // D=C A
extern VOID oD8(LPBYTE I); // B=A A
extern VOID oD9(LPBYTE I); // C=B A
extern VOID oDA(LPBYTE I); // A=C A
extern VOID oDB(LPBYTE I); // C=D A
extern VOID oDC(LPBYTE I); // ABEX
extern VOID oDD(LPBYTE I); // BCEX
extern VOID oDE(LPBYTE I); // CAEX
extern VOID oDF(LPBYTE I); // DCEX
extern VOID oE0(LPBYTE I); // A=A-B A
extern VOID oE1(LPBYTE I); // B=B-C A
extern VOID oE2(LPBYTE I); // C=C-A A
extern VOID oE3(LPBYTE I); // D=D-C A
extern VOID oE4(LPBYTE I); // A=A+1 A
extern VOID oE5(LPBYTE I); // B=B+1 A
extern VOID oE6(LPBYTE I); // C=C+1 A
extern VOID oE7(LPBYTE I); // D=D+1 A
extern VOID oE8(LPBYTE I); // B=B-A A
extern VOID oE9(LPBYTE I); // C=C-B A
extern VOID oEA(LPBYTE I); // A=A-C A
extern VOID oEB(LPBYTE I); // C=C-D A
extern VOID oEC(LPBYTE I); // A=B-A A
extern VOID oED(LPBYTE I); // B=C-B A
extern VOID oEE(LPBYTE I); // C=A-C A
extern VOID oEF(LPBYTE I); // D=C-D A
extern VOID oF0(LPBYTE I); // ASL A
extern VOID oF1(LPBYTE I); // BSL A
extern VOID oF2(LPBYTE I); // CSL A
extern VOID oF3(LPBYTE I); // DSL A
extern VOID oF4(LPBYTE I); // ASR A
extern VOID oF5(LPBYTE I); // BSR A
extern VOID oF6(LPBYTE I); // CSR A
extern VOID oF7(LPBYTE I); // DSR A
extern VOID oF8(LPBYTE I); // A=-A A
extern VOID oF9(LPBYTE I); // B=-B A
extern VOID oFA(LPBYTE I); // C=-C A
extern VOID oFB(LPBYTE I); // D=-D A
extern VOID oFC(LPBYTE I); // A=-A-1 A
extern VOID oFD(LPBYTE I); // B=-B-1 A
extern VOID oFE(LPBYTE I); // C=-C-1 A
extern VOID oFF(LPBYTE I); // D=-D-1 A
extern VOID o_invalid3(LPBYTE I);
extern VOID o_invalid4(LPBYTE I);
extern VOID o_invalid5(LPBYTE I);
extern VOID o_invalid6(LPBYTE I);
extern VOID o_goyes3(LPBYTE I);
extern VOID o_goyes5(LPBYTE I);
extern VOID o81B1(LPBYTE I); // beep patch

476
app/src/main/cpp/OPS.H Normal file
View file

@ -0,0 +1,476 @@
/*
* ops.h
*
* This file is part of Emu48
*
* Copyright (C) 1995 Sebastien Carlier
*
*/
#define NFunpack(a, b, f) Nunpack((a)+F_s[f], b, F_l[f])
#define NFread(a, b, f) Nread((a)+F_s[f], b, F_l[f])
#define NFwrite(a, b, f) Nwrite((a)+F_s[f], b, F_l[f])
#define NFcopy(a, b, f) memcpy((a)+F_s[f], (b)+F_s[f], F_l[f])
#define NFxchg(a, b, f) Nxchg((a)+F_s[f], (b)+F_s[f], F_l[f])
#define NFadd(a, b, f) Nadd((a)+F_s[f], (b)+F_s[f], F_l[f])
#define NFsub(a, b, f) Nsub((a)+F_s[f], (b)+F_s[f], F_l[f])
#define NFrsub(a, b, f) Nrsub((a)+F_s[f], (b)+F_s[f], F_l[f])
#define NFand(a, b, f) Nand((a)+F_s[f], (b)+F_s[f], F_l[f])
#define NFor(a, b, f) Nor((a)+F_s[f], (b)+F_s[f], F_l[f])
#define NFzero(a,f) memset((a)+F_s[f], 0, F_l[f])
#define NFpack(a, f) Npack((a)+F_s[f], F_l[f])
#define NFinc(a, f) Ninc(a, F_l[f], F_s[f])
#define NFdec(a, f) Ndec(a, F_l[f], F_s[f])
#define NFnot(a, f) Nnot((a)+F_s[f], F_l[f])
#define NFneg(a, f) Nneg((a)+F_s[f], F_l[f])
#define NFsl(a, f) Nsl((a)+F_s[f], F_l[f])
#define NFsr(a, f) Nsr((a)+F_s[f], F_l[f])
#define NFsrb(a, f) Nsrb((a)+F_s[f], F_l[f])
#define TFe(a, b, f) Te((a)+F_s[f], (b)+F_s[f], F_l[f])
#define TFa(a, b, f) Ta((a)+F_s[f], (b)+F_s[f], F_l[f])
#define TFb(a, b, f) Tb((a)+F_s[f], (b)+F_s[f], F_l[f])
#define TFz(a, f) Tz((a)+F_s[f], F_l[f])
#define TFne(a, b, f) Tne((a)+F_s[f], (b)+F_s[f], F_l[f])
#define TFae(a, b, f) Tae((a)+F_s[f], (b)+F_s[f], F_l[f])
#define TFbe(a, b, f) Tbe((a)+F_s[f], (b)+F_s[f], F_l[f])
#define TFnz(a, f) Tnz((a)+F_s[f], F_l[f])
static __inline LPBYTE FASTPTR(DWORD d)
{
static BYTE pbyNULL[21];
LPBYTE lpbyPage;
DWORD u, v;
d &= 0xFFFFF; // handle address overflows
u = d >> 12; // page
v = d & 0xFFF; // offset
if ( !(Chipset.IOCfig && ((d & 0xFFFC0) == Chipset.IOBase))
&& RMap[u] != NULL // page valid
&& ( v < 0x1000 - ARRAYSIZEOF(pbyNULL) // complete opcode inside page
// or next page continue linear addressing
|| (RMap[u] + 0x1000 == RMap[(u+1) & (ARRAYSIZEOF(RMap)-1)])
)
)
{
lpbyPage = RMap[u] + v; // full address
}
else
{
lpbyPage = pbyNULL; // memory allocation
Npeek(lpbyPage, d, ARRAYSIZEOF(pbyNULL)); // fill with data (LAHEX + 16 digits = longest opcode)
}
return lpbyPage;
}
static __inline void rstkpush(DWORD d)
{
Chipset.rstk[Chipset.rstkp] = d;
Chipset.rstkp=(Chipset.rstkp+1)&7;
}
static __inline DWORD rstkpop(VOID)
{
DWORD r;
Chipset.rstkp=(Chipset.rstkp-1)&7;
r = Chipset.rstk[Chipset.rstkp];
Chipset.rstk[Chipset.rstkp] = 0;
return r;
}
static __inline DWORD Npack(BYTE *a, UINT s)
{
DWORD r = 0;
while (s--) r = (r<<4)|a[s];
return r;
}
static __inline VOID Nunpack(BYTE *a, DWORD b, UINT s)
{
for (; s>0; --s) { *a++ = (BYTE)(b&0xf); b>>=4; }
}
static __inline QWORD Npack64(BYTE *a, UINT s)
{
QWORD r = 0;
while (s--) r = (r<<4)|a[s];
return r;
}
static __inline VOID Nunpack64(BYTE *a, QWORD b, UINT s)
{
UINT i;
for (i=0; i<s; i++) { a[i] = (BYTE)(b&0xf); b>>=4; }
}
static __inline void Nxchg(BYTE *a, BYTE *b, UINT s)
{
BYTE X[16];
memcpy(X, b, s);
memcpy(b, a, s);
memcpy(a, X, s);
}
static __inline void Ninc(BYTE *a, UINT s, UINT d)
{
UINT i;
if (Chipset.mode_dec)
{
BYTE c = 1;
for (i=d; i<s+d; ++i)
{
// no register wrap
_ASSERT(i < ARRAYSIZEOF(((CHIPSET *) NULL)->A));
// illegal number in dec mode
if (a[i] >= 10) a[i] &= 0x7;
a[i] += c;
c = (a[i] >= 10);
if (c) a[i] -= 10;
}
Chipset.carry = (c==1);
}
else
{
for (i=d; i<s+d; ++i)
{
// no register wrap
_ASSERT(i < ARRAYSIZEOF(((CHIPSET *) NULL)->A));
a[i]++;
if (a[i] < 16)
{
Chipset.carry = FALSE;
return;
}
a[i] -= 16;
}
Chipset.carry = TRUE;
}
}
static __inline void Ninc16(BYTE *a, UINT s, UINT d)
{
UINT i;
for (i=d; i<s+d; ++i)
{
a[i&0xf]++;
if (a[i&0xf] < 16)
{
Chipset.carry = FALSE;
return;
}
a[i&0xf] -= 16;
}
Chipset.carry = TRUE;
}
static __inline void Nincx(BYTE *a, UINT s)
{
UINT i;
for (i=0; i<s; ++i)
{
a[i]++;
if (a[i] < 16)
{
Chipset.carry = FALSE;
return;
}
a[i] -= 16;
}
Chipset.carry = TRUE;
}
static __inline void Ndec(BYTE *a, UINT s, UINT d)
{
UINT i;
BYTE cBase = Chipset.mode_dec ? 10 : 16;
for (i=d; i<s+d; ++i)
{
// no register wrap
_ASSERT(i < ARRAYSIZEOF(((CHIPSET *) NULL)->A));
a[i]--;
if ((a[i] & 0xF0) == 0) // check overflow
{
Chipset.carry = FALSE;
return;
}
a[i] += cBase;
}
Chipset.carry = TRUE;
}
static __inline void Ndec16(BYTE *a, UINT s, UINT d)
{
UINT i;
for (i=d; i<s+d; ++i)
{
a[i&0xf]--;
if (a[i&0xf] < 16)
{
Chipset.carry = FALSE;
return;
}
a[i&0xf] += 16;
}
Chipset.carry = TRUE;
}
static __inline void Nadd(BYTE *a, BYTE *b, UINT s)
{
UINT i;
BYTE c = 0;
BYTE cBase = Chipset.mode_dec ? 10 : 16;
for (i=0; i<s; ++i)
{
// illegal number in dec mode
if (a[i] >= cBase) a[i] &= 0x7;
a[i] += b[i] + c;
if (a[i] >= cBase)
{
a[i] -= cBase;
c = 1;
}
else
c = 0;
}
Chipset.carry = (c==1);
}
static __inline void Nsub(BYTE *a, BYTE *b, UINT s)
{
UINT i;
BYTE c = 0;
BYTE cBase = Chipset.mode_dec ? 10 : 16;
for (i=0; i<s; ++i)
{
a[i] = a[i] - b[i] - c;
if ((a[i] & 0xF0) != 0) // check overflow
{
a[i] += cBase;
// illegal number in dec mode
if ((a[i] & 0xF0) != 0) a[i] &= 0x7;
c = 1;
}
else
c = 0;
}
Chipset.carry = (c==1);
}
static __inline void Nrsub(BYTE *a, BYTE *b, UINT s)
{
UINT i;
BYTE c = 0;
BYTE cBase = Chipset.mode_dec ? 10 : 16;
for (i=0; i<s; ++i)
{
a[i] = b[i] - a[i] - c;
if ((a[i] & 0xF0) != 0) // check overflow
{
a[i] += cBase;
// illegal number in dec mode
if ((a[i] & 0xF0) != 0) a[i] &= 0x7;
c = 1;
}
else
c = 0;
}
Chipset.carry = (c==1);
}
static __inline void Nand(BYTE *a, BYTE *b, UINT s)
{
while (s--) a[s] &= b[s];
}
static __inline void Nor(BYTE *a, BYTE *b, UINT s)
{
while (s--) a[s] |= b[s];
}
static __inline void Nnot(BYTE *a, UINT s)
{
BYTE cBase = Chipset.mode_dec ? 9 : 15;
while (s--)
{
a[s] = cBase - a[s];
if ((a[s] & 0xF0) != 0) // check overflow (dec mode only)
a[s] &= 0x7;
}
Chipset.carry = FALSE;
}
static __inline void Nneg(BYTE *a, UINT s)
{
UINT i;
for (i=0; i<s && a[i]==0; ++i) { } // search for non-zero digit
if ((Chipset.carry = (i!=s))) // value was non-zero
{
BYTE cBase = Chipset.mode_dec ? 9 : 15;
_ASSERT(a[i] > 0); // check for non-zero digit
for (--a[i]; i<s; ++i)
{
a[i] = cBase - a[i];
if ((a[i] & 0xF0) != 0) // check overflow (dec mode only)
a[i] &= 0x7;
}
}
}
static __inline void Nsl(BYTE *a, UINT s)
{
while (--s) a[s] = a[s-1];
*a = 0;
}
static __inline void Nslc(BYTE *a, UINT s)
{
BYTE c = a[s-1];
while (--s) a[s] = a[s-1];
*a = c;
}
static __inline void Nsr(BYTE *a, UINT s)
{
if (*a) Chipset.HST |= SB;
while (--s) { *a = a[1]; a++; }
*a = 0;
}
static __inline void Nsrc(BYTE *a, UINT s)
{
BYTE c = *a;
if (c) Chipset.HST |= SB;
while (--s) { *a = a[1]; a++; }
*a = c;
}
static __inline void Nsrb(BYTE *a, UINT s)
{
if (*a & 1) Chipset.HST |= SB;
while (--s)
{
*a >>= 1;
*a |= ((a[1] & 1) << 3);
a++;
}
*a >>= 1;
}
static __inline void Nbit0(BYTE *a, UINT b)
{
a[b>>2] &= ~(1<<(b&3));
}
static __inline void Nbit1(BYTE *a, UINT b)
{
a[b>>2] |= 1<<(b&3);
}
static __inline void Tbit0(BYTE *a, UINT b)
{
Chipset.carry = ((a[b>>2] & (1<<(b&3))) == 0);
}
static __inline void Tbit1(BYTE *a, UINT b)
{
Chipset.carry = ((a[b>>2] & (1<<(b&3))) != 0);
}
static __inline void Te(BYTE *a, BYTE *b, UINT s)
{
while (s--)
{
if (a[s]!=b[s])
{
Chipset.carry = FALSE;
return;
}
}
Chipset.carry = TRUE;
}
static __inline void Tne(BYTE *a, BYTE *b, UINT s)
{
while (s--)
{
if (a[s]!=b[s])
{
Chipset.carry = TRUE;
return;
}
}
Chipset.carry = FALSE;
}
static __inline void Tz(BYTE *a, UINT s)
{
while (s--)
{
if (a[s]!=0)
{
Chipset.carry = FALSE;
return;
}
}
Chipset.carry = TRUE;
}
static __inline void Tnz(BYTE *a, UINT s)
{
while (s--)
{
if (a[s]!=0)
{
Chipset.carry = TRUE;
return;
}
}
Chipset.carry = FALSE;
}
static __inline void Ta(BYTE *a, BYTE *b, UINT s)
{
while (--s) if (a[s]!=b[s]) break;
Chipset.carry = (a[s]>b[s]);
}
static __inline void Tb(BYTE *a, BYTE *b, UINT s)
{
while (--s) if (a[s]!=b[s]) break;
Chipset.carry = (a[s]<b[s]);
}
static __inline void Tae(BYTE *a, BYTE *b, UINT s)
{
while (--s) if (a[s]!=b[s]) break;
Chipset.carry = (a[s]>=b[s]);
}
static __inline void Tbe(BYTE *a, BYTE *b, UINT s)
{
while (--s) if (a[s]!=b[s]) break;
Chipset.carry = (a[s]<=b[s]);
}

5
app/src/main/cpp/PCH.C Normal file
View file

@ -0,0 +1,5 @@
//
// PCH.C
//
#include "pch.h"

93
app/src/main/cpp/PCH.H Normal file
View file

@ -0,0 +1,93 @@
//
// PCH.H
//
#define _WIN32_IE 0x0200
#define _CRT_SECURE_NO_DEPRECATE
#define _CRTDBG_MAP_ALLOC
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <windows.h>
#include <tchar.h>
#include <shellapi.h>
#include <commctrl.h>
#include <shlobj.h>
#include <stdlib.h>
#include <malloc.h>
#include <stddef.h>
#include <ctype.h>
#include <stdio.h>
#include <direct.h>
#include <conio.h>
#include <crtdbg.h>
#if !defined VERIFY
#if defined _DEBUG
#define VERIFY(f) _ASSERT(f)
#else // _DEBUG
#define VERIFY(f) ((VOID)(f))
#endif // _DEBUG
#endif // _VERIFY
#if !defined INVALID_SET_FILE_POINTER
#define INVALID_SET_FILE_POINTER ((DWORD)-1)
#endif
#if !defined INVALID_FILE_ATTRIBUTES
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif
#if !defined GWLP_USERDATA
#define GWLP_USERDATA GWL_USERDATA
#endif
#if !defined GCLP_HCURSOR
#define GCLP_HCURSOR GCL_HCURSOR
#endif
#if !defined IDC_HAND // Win2k specific definition
#define IDC_HAND MAKEINTRESOURCE(32649)
#endif
#if _MSC_VER <= 1200 // missing type definition in the MSVC6.0 SDK and earlier
#define SetWindowLongPtr SetWindowLong
#define GetWindowLongPtr GetWindowLong
#define SetClassLongPtr SetClassLong
#define GetClassLongPtr GetClassLong
typedef SIZE_T DWORD_PTR, *PDWORD_PTR;
typedef ULONG ULONG_PTR, *PULONG_PTR;
typedef LONG LONG_PTR, *PLONG_PTR;
#endif
#if _MSC_VER >= 1400 // valid for VS2005 and later
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\" \
type='win32' \
name='Microsoft.Windows.Common-Controls' \
version='6.0.0.0' processorArchitecture='x86' \
publicKeyToken='6595b64144ccf1df' \
language='*'\"")
#elif defined _M_IA64
#pragma comment(linker,"/manifestdependency:\" \
type='win32' \
name='Microsoft.Windows.Common-Controls' \
version='6.0.0.0' processorArchitecture='ia64' \
publicKeyToken='6595b64144ccf1df' \
language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\" \
type='win32' \
name='Microsoft.Windows.Common-Controls' \
version='6.0.0.0' processorArchitecture='amd64' \
publicKeyToken='6595b64144ccf1df' \
language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\" \
type='win32' \
name='Microsoft.Windows.Common-Controls' \
version='6.0.0.0' processorArchitecture='*' \
publicKeyToken='6595b64144ccf1df' \
language='*'\"")
#endif
#endif

177
app/src/main/cpp/REDEYE.C Normal file
View file

@ -0,0 +1,177 @@
/*
* redeye.c
*
* This file is part of Emu48
*
* Copyright (C) 2011 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
#include "io.h"
#define ERR_CHAR 127 // character for transfer error
#define H1 0x78
#define H2 0xE6
#define H3 0xD5
#define H4 0x8B
// HP redeye correction masks
static CONST BYTE byEmask[] = { H1, H2, H3, H4 };
static __inline UINT MAX(UINT a, UINT b)
{
return (a>b)?a:b;
}
static __inline BYTE Parity(BYTE b)
{
b ^= (b >> 4);
b ^= (b >> 2);
b ^= (b >> 1);
return b & 1;
}
static __inline BYTE CreateCorrectionBits(BYTE b)
{
UINT i;
BYTE byVal = 0;
for (i = 0; i < ARRAYSIZEOF(byEmask);++i)
{
byVal <<= 1;
byVal |= Parity((BYTE) (b & byEmask[i]));
}
return byVal;
}
static __inline WORD CorrectData(WORD wData,WORD wMissed)
{
while ((wMissed & 0xFF) != 0) // clear every missed bit in data area
{
BYTE byBitMask;
// detect valid H(i) mask
WORD wMi = 0x800; // first M(i) bit
INT i = 0; // index to first H(i) mask
while (TRUE)
{
if ((wMissed & wMi) == 0) // possible valid mask
{
_ASSERT(i < ARRAYSIZEOF(byEmask));
// select bit to correct
byBitMask = wMissed & byEmask[i];
if (Parity(byBitMask)) // only one bit set (parity odd)
break; // -> valid H(i) mask
}
wMi >>= 1; // next M(i) bit
i++; // next H(i) mask
}
// correct bit with H(i) mask
wMissed ^= byBitMask; // clear this missed bit
// parity odd -> wrong data value
if (Parity((BYTE) ((wData & byEmask[i]) ^ ((wData & wMi) >> 8))))
wData ^= byBitMask; // correct value
}
return wData & 0xFF; // only data byte is correct
}
VOID IrPrinter(BYTE c)
{
static INT nFrame = 0; // frame counter
static DWORD dwData = 0; // half bit data container
static INT nStart = 0; // frame counter disabled
BOOL bLSRQ;
dwData = (dwData << 1) | (c & LBO); // grab the last 32 bit send through IR
// Led Service ReQuest on Led Buffer Empty enabled
bLSRQ = (Chipset.IORam[LCR] & ELBE) != 0;
IOBit(SRQ2,LSRQ,bLSRQ); // update LSRQ bit
if (bLSRQ) // interrupt on Led Buffer Empty enabled
{
Chipset.SoftInt = TRUE; // execute interrupt
bInterrupt = TRUE;
}
// HP40G and HP49G have no IR transmitter Led
if ((cCurrentRomType == 'E' && nCurrentClass == 40) || cCurrentRomType == 'X')
return;
if (nFrame == 0) // waiting for start bit condition
{
if ((dwData & 0x3F) == 0x07) // start bit condition (000111 pattern)
{
nStart = 1; // enable frame counter
}
}
if (nFrame == 24) // 24 half bit received
{
INT i;
WORD wData = 0; // data container
WORD wMissed = 0; // missed bit container
INT nCount = 0; // no. of missed bits
nFrame = 0; // reset for next character
nStart = 0; // disable frame counter
// separate to data and missed bits
for (i = 0; i < 12; ++i) // 12 bit frames
{
BYTE b = (BYTE) (dwData & 3); // last 2 half bits
if (b == 0x0 || b == 0x3) // illegal half bit combination
{
wMissed |= (1 << i); // this is a missed bit
++nCount; // incr. number of missed bits
}
else // valid data bit
{
wData |= ((b >> 1) << i); // add data bit
}
dwData >>= 2; // next 2 half bits
}
if (nCount <= 2) // error can be fixed
{
BYTE byOrgParity,byNewParity;
byOrgParity = wData >> 8; // the original parity information with missed bits
byNewParity = ~(wMissed >> 8); // missed bit mask for recalculated parity
if (nCount > 0) // error correction
{
wData = CorrectData(wData,wMissed);
}
wData &= 0xFF; // remove parity information
// recalculate parity data
byNewParity &= CreateCorrectionBits((BYTE) wData);
// wrong parity
if (byOrgParity != byNewParity)
wData = ERR_CHAR; // character for transfer error
}
else
{
wData = ERR_CHAR; // character for transfer error
}
SendByteUdp((BYTE) wData); // send data byte
return;
}
nFrame += nStart; // next frame
return;
}

253
app/src/main/cpp/RESOURCE.H Normal file
View file

@ -0,0 +1,253 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by Emu48.rc
//
#define IDM_DEBUG_SETTINGS 0x0010
#define IDI_EMU48 100
#define IDR_MENU 101
#define IDM_MENU 102
#define IDR_DEBUG 103
#define IDR_DEBUG_TOOLBAR 104
#define IDR_DEBUG_CODE 105
#define IDR_DEBUG_MEM 106
#define IDR_DEBUG_STACK 107
#define IDB_CHECKBOX 108
#define IDD_ABOUT 109
#define IDD_SET_GENERAL 110
#define IDD_SET_MEMORY 111
#define IDD_SET_PERIPHERAL 112
#define IDD_CHOOSEKML 113
#define IDD_KMLLOG 114
#define IDD_DISASM 115
#define IDD_DEBUG 116
#define IDD_NEWVALUE 117
#define IDD_ENTERADR 118
#define IDD_BREAKEDIT 119
#define IDD_ENTERBREAK 120
#define IDD_INSTRUCTIONS 121
#define IDD_WRITEONLYREG 122
#define IDD_FIND 123
#define IDD_PROFILE 124
#define IDD_RPLVIEW 125
#define IDD_MACROSET 126
#define IDD_DEBUG_MEMSAVE 127
#define IDD_DEBUG_MEMLOAD 128
#define IDD_DEBUG_SETTINGS 129
#define IDC_REALSPEED 1000
#define IDC_GRAYSCALE 1001
#define IDC_ALWAYSONTOP 1002
#define IDC_ACTFOLLOWSMOUSE 1003
#define IDC_SINGLEINSTANCE 1004
#define IDC_AUTOSAVE 1005
#define IDC_AUTOSAVEONEXIT 1006
#define IDC_OBJECTLOADWARNING 1007
#define IDC_SHOWTITLE 1008
#define IDC_SHOWMENU 1009
#define IDC_ALWAYSDISPLOG 1010
#define IDC_PORT1EN 1011
#define IDC_PORT1WR 1012
#define IDC_PORT2ISSHARED 1013
#define IDC_PORT2WR 1014
#define IDC_PORT2 1015
#define IDC_PORT2LOAD 1016
#define IDC_IR_ADDR 1017
#define IDC_IR_PORT 1018
#define IDC_WIRE 1019
#define IDC_IR 1020
#define IDC_EMUDIR 1021
#define IDC_EMUDIRSEL 1022
#define IDC_UPDATE 1023
#define IDC_KMLSCRIPT 1024
#define IDC_AUTHOR 1025
#define IDC_TITLE 1026
#define IDC_KMLLOG 1027
#define IDC_VERSION 1028
#define IDC_LICENSE 1029
#define IDC_DISASM_WIN 1030
#define IDC_DISASM_MODE_TEXT 1031
#define IDC_DISASM_MODE 1032
#define IDC_DISASM_MODULE 1033
#define IDC_DISASM_HP 1034
#define IDC_DISASM_CLASS 1035
#define IDC_ADDRESS 1036
#define IDC_DISASM_ADR 1037
#define IDC_DISASM_NEXT 1038
#define IDC_DISASM_COPY 1039
#define IDC_DEBUG_CODE 1040
#define IDC_STATIC_CODE 1041
#define IDC_STATIC_REGISTERS 1042
#define IDC_STATIC_MEMORY 1043
#define IDC_STATIC_STACK 1044
#define IDC_REG_A 1045
#define IDC_REG_B 1046
#define IDC_REG_C 1047
#define IDC_REG_D 1048
#define IDC_REG_R0 1049
#define IDC_REG_R1 1050
#define IDC_REG_R2 1051
#define IDC_REG_R3 1052
#define IDC_REG_R4 1053
#define IDC_REG_D0 1054
#define IDC_REG_D1 1055
#define IDC_REG_P 1056
#define IDC_REG_PC 1057
#define IDC_REG_OUT 1058
#define IDC_REG_IN 1059
#define IDC_REG_ST 1060
#define IDC_REG_CY 1061
#define IDC_REG_MODE 1062
#define IDC_REG_MP 1063
#define IDC_REG_SR 1064
#define IDC_REG_SB 1065
#define IDC_REG_XM 1066
#define IDC_MISC_INT 1067
#define IDC_MISC_KEY 1068
#define IDC_MISC_BS 1069
#define IDC_NEWVALUE 1070
#define IDC_ENTERADR 1071
#define IDC_DEBUG_MEM 1072
#define IDC_DEBUG_MEM_ADDR 1073
#define IDC_DEBUG_MEM_COL0 1074
#define IDC_DEBUG_MEM_COL1 1075
#define IDC_DEBUG_MEM_COL2 1076
#define IDC_DEBUG_MEM_COL3 1077
#define IDC_DEBUG_MEM_COL4 1078
#define IDC_DEBUG_MEM_COL5 1079
#define IDC_DEBUG_MEM_COL6 1080
#define IDC_DEBUG_MEM_COL7 1081
#define IDC_DEBUG_MEM_TEXT 1082
#define IDC_DEBUG_DATA_FILE 1083
#define IDC_DEBUG_DATA_BUT 1084
#define IDC_DEBUG_DATA_STARTADDR 1085
#define IDC_DEBUG_DATA_ENDADDR 1086
#define IDC_DEBUG_SET_SYMB 1087
#define IDC_DEBUG_SET_MODEL 1088
#define IDC_DEBUG_SET_FILE 1089
#define IDC_DEBUG_SET_BROWSE 1090
#define IDC_DEBUG_STACK 1091
#define IDC_STATIC_BREAKPOINT 1092
#define IDC_BREAKEDIT_ADD 1093
#define IDC_BREAKEDIT_DELETE 1094
#define IDC_BREAKEDIT_WND 1095
#define IDC_STATIC_MMU 1096
#define IDC_MMU_IO_A 1097
#define IDC_MMU_NCE2_A 1098
#define IDC_MMU_CE1_A 1099
#define IDC_MMU_CE2_A 1100
#define IDC_MMU_NCE3_A 1101
#define IDC_MMU_IO_S 1102
#define IDC_MMU_CE1_S 1103
#define IDC_MMU_CE2_S 1104
#define IDC_MMU_NCE2_S 1105
#define IDC_MMU_NCE3_S 1106
#define IDC_STATIC_MISC 1107
#define IDC_MISC_BS_TXT 1108
#define IDC_INSTR_TEXT 1109
#define IDC_INSTR_CODE 1110
#define IDC_INSTR_COPY 1111
#define IDC_INSTR_CLEAR 1112
#define IDC_PROFILE_LASTCYCLES 1113
#define IDC_PROFILE_LASTTIME 1114
#define IDC_BPCODE 1115
#define IDC_BPRPL 1116
#define IDC_BPACCESS 1117
#define IDC_BPREAD 1118
#define IDC_BPWRITE 1119
#define IDC_FIND_DATA 1120
#define IDC_FIND_PREV 1121
#define IDC_FIND_NEXT 1122
#define IDC_FIND_ASCII 1123
#define IDC_ADDR20_24 1124
#define IDC_ADDR25_27 1125
#define IDC_ADDR28_29 1126
#define IDC_ADDR30_34 1127
#define IDC_RPLVIEW_DATA 1128
#define IDC_MACRO_SLOW 1129
#define IDC_MACRO_FAST 1130
#define IDC_MACRO_SLIDER 1131
#define IDC_MACRO_REAL 1132
#define IDC_MACRO_MANUAL 1133
#define IDC_SOUND_SLIDER 1134
#define IDC_SOUND_DEVICE 1135
#define ID_FILE_NEW 40001
#define ID_FILE_OPEN 40002
#define ID_FILE_SAVE 40003
#define ID_FILE_SAVEAS 40004
#define ID_FILE_EXIT 40005
#define ID_VIEW_COPY 40006
#define ID_VIEW_SETTINGS 40007
#define ID_VIEW_RESET 40008
#define ID_OBJECT_LOAD 40009
#define ID_OBJECT_SAVE 40010
#define ID_ABOUT 40011
#define ID_HELP_TOPICS 40012
#define ID_FILE_CLOSE 40013
#define ID_BACKUP_SAVE 40014
#define ID_BACKUP_RESTORE 40015
#define ID_BACKUP_DELETE 40016
#define ID_VIEW_SCRIPT 40017
#define ID_STACK_COPY 40019
#define ID_STACK_PASTE 40020
#define ID_TOOL_DISASM 40021
#define ID_TOOL_DEBUG 40022
#define ID_TOOL_MACRO_RECORD 40023
#define ID_TOOL_MACRO_PLAY 40024
#define ID_TOOL_MACRO_STOP 40025
#define ID_TOOL_MACRO_SETTINGS 40026
#define ID_DEBUG_RUN 40027
#define ID_DEBUG_RUNCURSOR 40028
#define ID_DEBUG_STEP 40029
#define ID_DEBUG_STEPOVER 40030
#define ID_DEBUG_BREAK 40031
#define ID_DEBUG_STEPOUT 40032
#define ID_DEBUG_CANCEL 40033
#define ID_BREAKPOINTS_SETBREAK 40034
#define ID_BREAKPOINTS_CODEEDIT 40035
#define ID_BREAKPOINTS_CLEARALL 40036
#define ID_BREAKPOINTS_NOP3 40037
#define ID_BREAKPOINTS_DOCODE 40038
#define ID_BREAKPOINTS_RPL 40039
#define ID_DEBUG_CODE_GOADR 40040
#define ID_DEBUG_CODE_GOPC 40041
#define ID_DEBUG_CODE_SETPCTOSELECT 40042
#define ID_DEBUG_CODE_PREVPCO 40043
#define ID_DEBUG_CODE_NEXTPCO 40044
#define ID_DEBUG_MEM_GOADR 40045
#define ID_DEBUG_MEM_GOPC 40046
#define ID_DEBUG_MEM_GOD0 40047
#define ID_DEBUG_MEM_GOD1 40048
#define ID_DEBUG_MEM_GOSTACK 40049
#define ID_DEBUG_MEM_FNONE 40050
#define ID_DEBUG_MEM_FADDR 40051
#define ID_DEBUG_MEM_FPC 40052
#define ID_DEBUG_MEM_FD0 40053
#define ID_DEBUG_MEM_FD1 40054
#define ID_DEBUG_MEM_FIND 40055
#define ID_DEBUG_MEM_MAP 40056
#define ID_DEBUG_MEM_NCE1 40057
#define ID_DEBUG_MEM_NCE2 40058
#define ID_DEBUG_MEM_CE1 40059
#define ID_DEBUG_MEM_CE2 40060
#define ID_DEBUG_MEM_NCE3 40061
#define ID_DEBUG_MEM_SAVE 40062
#define ID_DEBUG_MEM_LOAD 40063
#define ID_DEBUG_MEM_RPLVIEW 40064
#define ID_DEBUG_STACK_PUSH 40065
#define ID_DEBUG_STACK_POP 40066
#define ID_DEBUG_STACK_MODIFY 40067
#define ID_INTR_STEPOVERINT 40068
#define ID_INFO_LASTINSTRUCTIONS 40069
#define ID_INFO_PROFILE 40070
#define ID_INFO_WRITEONLYREG 40071
#define ID_FILE_MRU_FILE1 40100
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 130
#define _APS_NEXT_COMMAND_VALUE 40072
#define _APS_NEXT_CONTROL_VALUE 1136
#define _APS_NEXT_SYMED_VALUE 109
#endif
#endif

459
app/src/main/cpp/RPL.C Normal file
View file

@ -0,0 +1,459 @@
/*
* rpl.c
*
* This file is part of Emu48
*
* Copyright (C) 1995 Sebastien Carlier
*
*/
#include "pch.h"
#include "Emu48.h"
#include "ops.h"
#include "io.h"
//| 38G | 39G | 40G | 48SX | 48GX | 49G | Name
//#F0688 #806E9 #806E9 #7056A #806E9 #806E9 =TEMPOB
//#F068D #806EE #806EE #7056F #806EE #806EE =TEMPTOP
//#F0692 #806F3 #806F3 #70574 #806F3 #806F3 =RSKTOP (B)
//#F0697 #806F8 #806F8 #70579 #806F8 #806F8 =DSKTOP (D1)
//#F069C #806FD #806FD #7057E #806FD #806FD =EDITLINE
//#F0DEA #80E9B #80E9B #7066E #807ED #80E9B =AVMEM (D)
//#F0705 #8076B #8076B #705B0 #8072F #8076B =INTRPPTR (D0)
//#F0E42 #80F02 #80F02 #706C5 #80843 #80F02 =SystemFlags
#define TEMPOB ((cCurrentRomType=='S')?0x7056A:0x806E9)
#define TEMPTOP ((cCurrentRomType=='S')?0x7056F:0x806EE)
#define RSKTOP ((cCurrentRomType=='S')?0x70574:0x806F3)
#define DSKTOP ((cCurrentRomType=='S')?0x70579:0x806F8)
#define EDITLINE ((cCurrentRomType=='S')?0x7057E:0x806FD)
// CdB for HP: add apples
#define AVMEM ((cCurrentRomType!='X' && cCurrentRomType!='2' && cCurrentRomType!='Q')?((cCurrentRomType=='S')?0x7066E:0x807ED):0x80E9B)
#define INTRPPTR ((cCurrentRomType!='X' && cCurrentRomType!='2' && cCurrentRomType!='Q')?((cCurrentRomType=='S')?0x705B0:0x8072F):0x8076B)
#define SYSTEMFLAGS ((cCurrentRomType!='X' && cCurrentRomType!='2' && cCurrentRomType!='Q')?((cCurrentRomType=='S')?0x706C5:0x80843):0x80F02)
#define DOINT 0x02614 // Precision Integer (HP49G)
#define DOLNGREAL 0x0263A // Precision Real (HP49G)
#define DOLNGCMP 0x02660 // Precision Complex (HP49G)
#define DOMATRIX 0x02686 // Symbolic matrix (HP49G)
#define DOFLASHP 0x026AC // Flash PTR (HP49G)
#define DOAPLET 0x026D5 // Aplet (HP49G)
#define DOMINIFONT 0x026FE // Mini Font (HP49G)
#define DOBINT 0x02911 // System Binary
#define DOREAL 0x02933 // Real
#define DOEREL 0x02955 // Long Real
#define DOCMP 0x02977 // Complex
#define DOECMP 0x0299D // Long Complex
#define DOCHAR 0x029BF // Character
#define DOARRY 0x029E8 // Array
#define DOLNKARRY 0x02A0A // Linked Array
#define DOCSTR 0x02A2C // String
#define DOHSTR 0x02A4E // Binary Integer
#define DOLIST 0x02A74 // List
#define DORRP 0x02A96 // Directory
#define DOSYMB 0x02AB8 // Algebraic
#define DOEXT 0x02ADA // Unit
#define DOTAG 0x02AFC // Tagged
#define DOGROB 0x02B1E // Graphic
#define DOLIB 0x02B40 // Library
#define DOBAK 0x02B62 // Backup
#define DOEXT0 0x02B88 // Library Data
#define DOEXT1 0x02BAA // Reserved 1, ACcess PoinTeR (HP48GX and later)
#define DOEXT2 0x02BCC // Reserved 2, Font (HP49G)
#define DOEXT3 0x02BEE // Reserved 3
#define DOEXT4 0x02C10 // Reserved 4
#define DOCOL 0x02D9D // Program
#define DOCODE 0x02DCC // Code
#define DOIDNT 0x02E48 // Global Name
#define DOLAM 0x02E6D // Local Name
#define DOROMP 0x02E92 // XLIB Name
#define SEMI 0x0312B // ;
#define GARBAGECOL 0x0613E // =GARBAGECOL entry for HP48S/G and HP49G
// check for Metakernel version
#define METAKERNEL Metakernel()
// search for "MDGKER:MK2.30" or "MDGKER:PREVIE" in port1 of a HP48GX
static BOOL Metakernel(VOID)
{
BOOL bMkDetect = FALSE;
// card in slot1 of a HP48GX enabled
if (cCurrentRomType=='G' && Port1 && Chipset.cards_status & PORT1_PRESENT)
{
// check for Metakernel string "MDGKER:"
if (!strncmp((LPCSTR) &Port1[12],"\xD\x4\x4\x4\x7\x4\xB\x4\x5\x4\x2\x5\xA\x3",14))
{
bMkDetect = TRUE; // Metakernel detected
// check for "MK"
if (!strncmp((LPCSTR) &Port1[26],"\xD\x4\xB\x4",4))
{
// get version number
WORD wVersion = ((Port1[30] * 10) + Port1[34]) * 10
+ Port1[36];
// version newer then V2.30, then compatible with HP OS
bMkDetect = (wVersion <= 230);
}
}
}
return bMkDetect;
}
static DWORD RPL_GarbageCol(VOID) // RPL variables must be in system RAM
{
CHIPSET OrgChipset;
DWORD dwAVMEM;
// only for HP48SX, HP48GX, HP49G, HP48gII and HP49g+
_ASSERT( cCurrentRomType == 'S' || cCurrentRomType == 'G' || cCurrentRomType == 'X'
|| cCurrentRomType == '2' || cCurrentRomType == 'Q');
OrgChipset = Chipset; // save original chipset
// entry for =GARBAGECOL
Chipset.P = 0; // P=0
Chipset.mode_dec = FALSE; // hex mode
Chipset.pc = GARBAGECOL; // =GARBAGECOL entry
rstkpush(0xFFFFF); // return address for stopping
while (Chipset.pc != 0xFFFFF) // wait for stop address
{
EvalOpcode(FASTPTR(Chipset.pc)); // execute opcode
}
dwAVMEM = Npack(Chipset.C,5); // available AVMEM
Chipset = OrgChipset; // restore original chipset
return dwAVMEM;
}
BOOL RPL_GetSystemFlag(INT nFlag)
{
DWORD dwAddr;
BYTE byMask,byFlag;
_ASSERT(nFlag > 0); // first flag is 1
// calculate memory address and bit mask
dwAddr = SYSTEMFLAGS + (nFlag - 1) / 4;
byMask = 1 << ((nFlag - 1) & 0x3);
Npeek(&byFlag,dwAddr,sizeof(byFlag));
return (byFlag & byMask) != 0;
}
DWORD RPL_SkipOb(DWORD d)
{
BYTE X[8];
DWORD n, l;
Npeek(X,d,5);
n = Npack(X, 5); // read prolog
switch (n)
{
case DOFLASHP: l = (cCurrentRomType!='X' && cCurrentRomType!='2' && cCurrentRomType!='Q') ? 5 : 12; break; // Flash PTR (HP49G) // CdB for HP: add apples
case DOBINT: l = 10; break; // System Binary
case DOREAL: l = 21; break; // Real
case DOEREL: l = 26; break; // Long Real
case DOCMP: l = 37; break; // Complex
case DOECMP: l = 47; break; // Long Complex
case DOCHAR: l = 7; break; // Character
case DOROMP: l = 11; break; // XLIB Name
case DOMATRIX: // Symbolic matrix (HP49G)
if (cCurrentRomType!='X' && cCurrentRomType!='2' && cCurrentRomType!='Q') // CdB for HP: add apples
{
l = 5;
break;
}
case DOLIST: // List
case DOSYMB: // Algebraic
case DOEXT: // Unit
case DOCOL: // Program
n=d+5;
do
{
d=n; n=RPL_SkipOb(d);
} while (d!=n);
return n+5;
case SEMI: return d; // SEMI
case DOIDNT: // Global Name
case DOLAM: // Local Name
case DOTAG: // Tagged
Npeek(X,d+5,2); n = 7 + Npack(X,2)*2;
return RPL_SkipOb(d+n);
case DORRP: // Directory
d+=8;
n = Read5(d);
if (n==0)
{
return d+5;
}
else
{
d+=n;
Npeek(X,d,2);
n = Npack(X,2)*2 + 4;
return RPL_SkipOb(d+n);
}
case DOINT: // Precision Integer (HP49G)
case DOAPLET: // Aplet (HP49G)
case DOMINIFONT: // Mini Font (HP49G)
if (cCurrentRomType!='X' && cCurrentRomType!='2' && cCurrentRomType!='Q') // CdB for HP: add apples
{
l = 5;
break;
}
case DOARRY: // Array
case DOLNKARRY: // Linked Array
case DOCSTR: // String
case DOHSTR: // Binary Integer
case DOGROB: // Graphic
case DOLIB: // Library
case DOBAK: // Backup
case DOEXT0: // Library Data
case DOEXT1: // Reserved 1
if (n == DOEXT1 && cCurrentRomType != 'S')
{
// on HP48G series and later interpreted as DOACPTR
l = 15; break; // ACcess PoinTeR
break;
}
case DOEXT2: // Reserved 2, Font (HP49G)
case DOEXT3: // Reserved 3
case DOEXT4: // Reserved 4
case DOCODE: // Code
l = 5+Read5(d+5);
break;
case DOLNGREAL: // Precision Real (HP49G)
l = 5;
if (cCurrentRomType=='X')
{
l += Read5(d+l);
l += Read5(d+l);
}
break;
case DOLNGCMP: // Precision Complex (HP49G)
l = 5;
if (cCurrentRomType=='X')
{
l += Read5(d+l);
l += Read5(d+l);
l += Read5(d+l);
l += Read5(d+l);
}
break;
default: return d+5;
}
return d+l;
}
DWORD RPL_ObjectSize(BYTE *o,DWORD s)
{
#define SERIES49 (cCurrentRomType=='X' || cCurrentRomType=='2' || cCurrentRomType=='Q')
DWORD n, l = 0;
if (s < 5) return BAD_OB; // size too small for prolog
n = Npack(o,5); // read prolog
switch (n)
{
case DOFLASHP: l = (SERIES49) ? 12 : 5; break; // Flash PTR (HP49G)
case DOBINT: l = 10; break; // System Binary
case DOREAL: l = 21; break; // Real
case DOEREL: l = 26; break; // Long Real
case DOCMP: l = 37; break; // Complex
case DOECMP: l = 47; break; // Long Complex
case DOCHAR: l = 7; break; // Character
case DOROMP: l = 11; break; // XLIB Name
case DOMATRIX: // Symbolic matrix (HP49G)
if (!SERIES49)
{
l = 5;
break;
}
case DOLIST: // List
case DOSYMB: // Algebraic
case DOEXT: // Unit
case DOCOL: // Program
n = 5; // prolog length
do
{
l += n;
if (l > s) return BAD_OB; // prevent negative size argument
n = RPL_ObjectSize(o+l,s-l); // get new object
if (n == BAD_OB) return BAD_OB; // buffer overflow
}
while (n);
l += 5;
break;
case SEMI: l = 0; break; // SEMI
case DOIDNT: // Global Name
case DOLAM: // Local Name
case DOTAG: // Tagged
if (s < 5 + 2) return BAD_OB;
l = 7 + Npack(o+5,2) * 2; // prolog + name length
if (l > s) return BAD_OB; // prevent negative size argument
n = RPL_ObjectSize(o+l,s-l); // get new object
if (n == BAD_OB) return BAD_OB; // buffer overflow
l += n;
break;
case DORRP: // Directory
if (s < 8 + 5) return BAD_OB;
n = Npack(o+8,5);
if (n == 0) // empty dir
{
l = 13;
}
else
{
l = 8 + n;
if (s < l + 2) return BAD_OB;
n = Npack(o+l,2) * 2 + 4;
l += n;
if (l > s) return BAD_OB; // prevent negative size argument
n = RPL_ObjectSize(o+l,s-l); // next rrp
if (n == BAD_OB) return BAD_OB; // buffer overflow
l += n;
}
break;
case DOINT: // Precision Integer (HP49G)
case DOAPLET: // Aplet (HP49G)
case DOMINIFONT: // Mini Font (HP49G)
if (!SERIES49)
{
l = 5;
break;
}
case DOARRY: // Array
case DOLNKARRY: // Linked Array
case DOCSTR: // String
case DOHSTR: // Binary Integer
case DOGROB: // Graphic
case DOLIB: // Library
case DOBAK: // Backup
case DOEXT0: // Library Data
case DOEXT1: // Reserved 1
if (n == DOEXT1 && cCurrentRomType != 'S')
{
// on HP48G series and later interpreted as DOACPTR
l = 15; break; // ACcess PoinTeR
break;
}
case DOEXT2: // Reserved 2, Font (HP49G)
case DOEXT3: // Reserved 3
case DOEXT4: // Reserved 4
case DOCODE: // Code
if (s < 5 + 5) return BAD_OB;
l = 5 + Npack(o+5,5);
break;
case DOLNGREAL: // Precision Real (HP49G)
l = 5;
if (SERIES49)
{
if (s < l + 5) return BAD_OB;
l += Npack(o+l,5);
if (s < l + 5) return BAD_OB;
l += Npack(o+l,5);
}
break;
case DOLNGCMP: // Precision Complex (HP49G)
l = 5;
if (SERIES49)
{
if (s < l + 5) return BAD_OB;
l += Npack(o+l,5);
if (s < l + 5) return BAD_OB;
l += Npack(o+l,5);
if (s < l + 5) return BAD_OB;
l += Npack(o+l,5);
if (s < l + 5) return BAD_OB;
l += Npack(o+l,5);
}
break;
default: l = 5;
}
return (s >= l) ? l : BAD_OB;
#undef SERIES49
}
DWORD RPL_CreateTemp(DWORD l,BOOL bGarbageCol)
{
DWORD a, b, c;
BYTE *p;
l += 6; // memory for link field (5) + marker (1) and end
b = Read5(RSKTOP); // tail address of rtn stack
c = Read5(DSKTOP); // top of data stack
if ((b+l)>c && bGarbageCol) // there's not enough memory to move DSKTOP
{
RPL_GarbageCol(); // do a garbage collection
b = Read5(RSKTOP); // reload tail address of rtn stack
c = Read5(DSKTOP); // reload top of data stack
}
if ((b+l)>c) return 0; // check if now there's enough memory to move DSKTOP
a = Read5(TEMPTOP); // tail address of top object
Write5(TEMPTOP, a+l); // adjust new end of top object
Write5(RSKTOP, b+l); // adjust new end of rtn stack
Write5(AVMEM, (c-b-l)/5); // calculate free memory (*5 nibbles)
p = (LPBYTE) malloc(b-a); // move down rtn stack
Npeek(p,a,b-a);
Nwrite(p,a+l,b-a);
free(p);
Write5(a+l-5,l); // set object length field
return (a+1); // return base address of new object
}
UINT RPL_Depth(VOID)
{
return (Read5(EDITLINE) - Read5(DSKTOP)) / 5 - 1;
}
DWORD RPL_Pick(UINT l)
{
DWORD stkp;
_ASSERT(l > 0); // first stack element is one
if (l == 0) return 0;
if (METAKERNEL) ++l; // Metakernel support
if (RPL_Depth() < l) return 0; // not enough elements on stack
stkp = Read5(DSKTOP) + (l-1)*5;
return Read5(stkp); // return object address
}
VOID RPL_Replace(DWORD n)
{
DWORD stkp;
stkp = Read5(DSKTOP);
if (METAKERNEL) stkp+=5; // Metakernel support
Write5(stkp,n);
return;
}
VOID RPL_Push(UINT l,DWORD n)
{
UINT i;
DWORD stkp, avmem;
if (l > RPL_Depth() + 1) return; // invalid stack level
avmem = Read5(AVMEM); // amount of free memory
if (avmem == 0) return; // no memory free
avmem--; // fetch memory
Write5(AVMEM,avmem); // save new amount of free memory
if (METAKERNEL) ++l; // Metakernel, save MK object on stack level 1
stkp = Read5(DSKTOP) - 5; // get pointer of new stack level 1
Write5(DSKTOP,stkp); // save it
for (i = 1; i < l; ++i) // move down stack level entries before insert pos
{
Write5(stkp,Read5(stkp+5)); // move down stack level entry
stkp += 5; // next stack entry
}
Write5(stkp,n); // save pointer of new object on given stack level
return;
}

388
app/src/main/cpp/SERIAL.C Normal file
View file

@ -0,0 +1,388 @@
/*
* Serial.c
*
* This file is part of Emu48
*
* Copyright (C) 1998 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
#include "io.h"
#define INTERRUPT ((void)(Chipset.SoftInt=TRUE,bInterrupt=TRUE))
// state of USRQ
#define NINT2ERBZ ((Chipset.IORam[IOC] & (SON | ERBZ)) == (SON | ERBZ) && (Chipset.IORam[RCS] & RBZ) != 0)
#define NINT2ERBF ((Chipset.IORam[IOC] & (SON | ERBF)) == (SON | ERBF) && (Chipset.IORam[RCS] & RBF) != 0)
#define NINT2ETBE ((Chipset.IORam[IOC] & (SON | ETBE)) == (SON | ETBE) && (Chipset.IORam[TCS] & TBF) == 0)
#define NINT2USRQ (NINT2ERBZ || NINT2ERBF || NINT2ETBE)
static HANDLE hComm = NULL;
static HANDLE hCThreadTxd;
static HANDLE hCThreadEv;
static HANDLE hEventTxd;
static BOOL bWriting;
static BYTE tbr;
static BOOL bReading;
static BYTE cBuffer[32];
static WORD nRp;
static DWORD dwBytesRead;
static DWORD WINAPI TransmitThread(LPVOID pParam)
{
OVERLAPPED osWr = { 0 };
osWr.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
while (bWriting)
{
WaitForSingleObject(hEventTxd,INFINITE);
if (bWriting)
{
DWORD dwWritten;
if (!WriteFile(hComm,(LPCVOID) &tbr,1,&dwWritten,&osWr))
if (GetLastError() == ERROR_IO_PENDING)
GetOverlappedResult(hComm,&osWr,&dwWritten,TRUE);
}
}
CloseHandle(osWr.hEvent); // close write event handle
return 0;
UNREFERENCED_PARAMETER(pParam);
}
static DWORD WINAPI EventThread(LPVOID pParam)
{
DWORD dwEvent;
bReading = TRUE; // flag for SerialThread started
while (bReading)
{
_ASSERT(hComm != NULL);
WaitCommEvent(hComm,&dwEvent,NULL); // wait for serial event
if (dwEvent & EV_RXCHAR) // signal char received
{
CommReceive(); // get data
// interrupt request and emulation thread down
if (Chipset.SoftInt && Chipset.Shutdn)
{
Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode
SetEvent(hEventShutdn); // wake up emulation thread
}
}
if (dwEvent & EV_TXEMPTY) // signal transmit buffer empty
{
IOBit(TCS,TBZ,FALSE); // clear transmitter busy bit
CommTransmit(); // check for new char to transmit
}
if (dwEvent & EV_ERR) // signal error received
{
DWORD dwError;
ClearCommError(hComm,&dwError,NULL);
if (dwError & (CE_FRAME | CE_OVERRUN | CE_BREAK))
IOBit(RCS,RER,TRUE); // receiver error
}
}
return 0;
UNREFERENCED_PARAMETER(pParam);
}
BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort)
{
COMMTIMEOUTS CommTimeouts = { MAXDWORD, 0L, 0L, 0L, 0L };
LPCTSTR strPort = (Chipset.IORam[IR_CTRL] & EIRU) ? strIrPort : strWirePort;
_ASSERT(Chipset.IORam[IOC] & SON); // UART on
CommClose(); // close port if already open
if (lstrcmp(strPort, _T(NO_SERIAL))) // port defined
{
TCHAR szDevice[256] = _T("\\\\.\\");
// check if device buffer is big enough
_ASSERT(lstrlen(szDevice) + lstrlen(strPort) < (INT) ARRAYSIZEOF(szDevice));
if (lstrlen(szDevice) + lstrlen(strPort) >= (INT) ARRAYSIZEOF(szDevice))
return hComm != NULL;
_tcscat(szDevice,strPort); // device name
hComm = CreateFile(szDevice,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (hComm != INVALID_HANDLE_VALUE)
{
DWORD dwThreadId;
nRp = 0; // reset receiver state
dwBytesRead = 0L;
SetCommTimeouts(hComm,&CommTimeouts);
CommSetBaud();
CommTxBRK(); // update BRK condition
// event to transmit character
hEventTxd = CreateEvent(NULL,FALSE,FALSE,NULL);
// create char transmit handler
bWriting = TRUE;
hCThreadTxd = CreateThread(NULL,0,&TransmitThread,NULL,CREATE_SUSPENDED,&dwThreadId);
_ASSERT(hCThreadTxd);
SetThreadPriority(hCThreadTxd,THREAD_PRIORITY_ABOVE_NORMAL);
ResumeThread(hCThreadTxd); // start thread
// create Comm event handler
bReading = FALSE;
SetCommMask(hComm,EV_RXCHAR | EV_TXEMPTY | EV_ERR); // event on RX, TX, error
hCThreadEv = CreateThread(NULL,0,&EventThread,NULL,CREATE_SUSPENDED,&dwThreadId);
_ASSERT(hCThreadEv);
SetThreadPriority(hCThreadEv,THREAD_PRIORITY_ABOVE_NORMAL);
ResumeThread(hCThreadEv); // start thread
while (!bReading) Sleep(0); // wait for SerialThread started
}
else
hComm = NULL;
}
#if defined DEBUG_SERIAL
{
TCHAR buffer[256];
wsprintf(buffer,_T("COM port %s.\n"),hComm ? _T("opened"): _T("open error"));
OutputDebugString(buffer);
}
#endif
return hComm != NULL;
}
VOID CommClose(VOID)
{
if (hComm != NULL) // port open
{
// workaround to fix problems with some Kermit server programs
// reason: on one hand we have the character transmitting time base on the
// selected baudrate, on the other hand the time between sending the last
// character and closing the port. The last time is much longer on the real
// calculator than on the emulator running at full speed, therefore the
// slow down time on the emulator
Sleep(25); // slow down time
bReading = FALSE; // kill event thread
SetCommMask(hComm,0L); // clear all events and force WaitCommEvent to return
WaitForSingleObject(hCThreadEv,INFINITE);
CloseHandle(hCThreadEv);
bWriting = FALSE; // kill write thread
SetEvent(hEventTxd); // continue write thread
WaitForSingleObject(hCThreadTxd,INFINITE);
CloseHandle(hCThreadTxd);
CloseHandle(hEventTxd); // close Txd event
CloseHandle(hComm); // close port
hComm = NULL;
#if defined DEBUG_SERIAL
OutputDebugString(_T("COM port closed.\n"));
#endif
}
return;
}
VOID CommSetBaud(VOID)
{
if (hComm != NULL)
{
const DWORD dwBaudrates[] = { 1200, 1920, 2400, 3840, 4800, 7680, 9600, 15360,
14400, 19200, 38400, 57600, 115200, 115200, 115200, 115200 };
DCB dcb;
UINT uBaudIndex;
uBaudIndex = isModelApple(cCurrentRomType)
? Chipset.IORam[BAUD]
: Chipset.IORam[BAUD] & 0x7;
ZeroMemory(&dcb,sizeof(dcb));
dcb.DCBlength = sizeof(dcb);
dcb.BaudRate = dwBaudrates[uBaudIndex];
dcb.fBinary = TRUE;
dcb.fParity = TRUE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fDsrSensitivity = FALSE;
dcb.fOutX = FALSE;
dcb.fErrorChar = FALSE;
dcb.fNull = FALSE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fAbortOnError = FALSE; // may changed in further implementations
dcb.ByteSize = 8;
dcb.Parity = NOPARITY; // no parity check, emulated by software
dcb.StopBits = TWOSTOPBITS;
#if defined DEBUG_SERIAL
{
TCHAR buffer[256];
wsprintf(buffer,_T("CommsetBaud: %ld\n"),dcb.BaudRate);
OutputDebugString(buffer);
}
#endif
SetCommState(hComm,&dcb);
}
return;
}
BOOL UpdateUSRQ(VOID) // USRQ handling
{
BOOL bUSRQ = NINT2USRQ;
IOBit(SRQ1,USRQ,bUSRQ); // update USRQ bit
return bUSRQ;
}
VOID CommTxBRK(VOID)
{
if (Chipset.IORam[TCS] & BRK) // BRK condition
{
if (hComm != NULL) // com port open
{
// abort data transfer
PurgeComm(hComm,PURGE_TXABORT | PURGE_TXCLEAR);
SetCommBreak(hComm); // set into BRK state
}
// TBF and TBZ bits of TCS are undefined
if (Chipset.IORam[TCS] & LPB) // is loopback bit set
{
dwBytesRead = nRp = 0; // clear receive buffer
cBuffer[dwBytesRead++] = 0; // save character in receive buffer
CommReceive(); // receive available byte
IOBit(RCS,RER,TRUE); // receiver error (no stop bit)
}
}
else
{
if (hComm != NULL) // com port open
{
ClearCommBreak(hComm); // clear BRK state
}
}
return;
}
VOID CommTransmit(VOID)
{
BOOL bTxChar = FALSE;
EnterCriticalSection(&csTxdLock);
if ( (Chipset.IORam[TCS] & TBZ) == 0 // transmitter not busy
&& (Chipset.IORam[TCS] & TBF) != 0) // transmit buffer full
{
tbr = (Chipset.IORam[TBR_MSB] << 4) | Chipset.IORam[TBR_LSB];
IOBit(TCS,TBF,FALSE); // clear transmit buffer full bit
IOBit(TCS,TBZ,TRUE); // set transmitter busy bit
bTxChar = TRUE;
}
LeaveCriticalSection(&csTxdLock);
if (bTxChar) // character to transmit
{
#if defined DEBUG_SERIAL
{
TCHAR buffer[256];
if (isprint(tbr))
wsprintf(buffer,_T("-> '%c'\n"),tbr);
else
wsprintf(buffer,_T("-> %02X\n"),tbr);
OutputDebugString(buffer);
}
#endif
if (Chipset.IORam[TCS] & LPB) // is loopback bit set
{
if (dwBytesRead == 0) nRp = 0; // no character received, reset read pointer
cBuffer[nRp+dwBytesRead] = tbr; // save character in receive buffer
++dwBytesRead;
CommReceive(); // receive available byte
}
if (hComm != NULL) // com port open
{
SetEvent(hEventTxd); // write TBR byte
}
else
{
IOBit(TCS,TBZ,FALSE); // clear transmitter busy bit
}
}
if (UpdateUSRQ()) // update USRQ bit
INTERRUPT;
return;
}
VOID CommReceive(VOID)
{
OVERLAPPED os = { 0 };
if (!(Chipset.IORam[IOC] & SON)) // UART off
{
dwBytesRead = 0L; // no bytes received
return;
}
EnterCriticalSection(&csRecvLock);
do
{
if (Chipset.IORam[RCS] & RBF) // receive buffer full
break;
// reject reading if com port is closed and not whole operation
if (hComm && dwBytesRead == 0L) // com port open and buffer empty
{
if (ReadFile(hComm,&cBuffer,sizeof(cBuffer),&dwBytesRead,&os) == FALSE)
dwBytesRead = 0L;
else // bytes received
nRp = 0; // reset read pointer
}
if (dwBytesRead == 0L) // receive buffer empty
break;
#if defined DEBUG_SERIAL
{
TCHAR buffer[256];
if (isprint(cBuffer[nRp]))
wsprintf(buffer,_T("<- '%c'\n"),cBuffer[nRp]);
else
wsprintf(buffer,_T("<- %02X\n"),cBuffer[nRp]);
OutputDebugString(buffer);
}
#endif
Chipset.IORam[RBR_MSB] = (cBuffer[nRp] >> 4);
Chipset.IORam[RBR_LSB] = (cBuffer[nRp] & 0x0f);
++nRp;
--dwBytesRead;
Chipset.IORam[RCS] |= RBF; // receive buffer full
if (UpdateUSRQ()) // update USRQ bit
INTERRUPT;
}
while (FALSE);
LeaveCriticalSection(&csRecvLock);
return;
}

313
app/src/main/cpp/SETTINGS.C Normal file
View file

@ -0,0 +1,313 @@
/*
* settings.c
*
* This file is part of Emu48
*
* Copyright (C) 2000 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
#include "i28f160.h"
// #define REGISTRY // use registry instead of *.ini file
//################
//#
//# Low level subroutines
//#
//################
#if !defined REGISTRY
// INI-file handling
#if !defined EMU48_INI
#define EMU48_INI "Emu48.ini"
#endif
#define ReadString(sec,key,dv,v,sv) GetPrivateProfileString(sec,key,dv,v,sv,_T(EMU48_INI))
#define ReadInt(sec,key,dv) GetPrivateProfileInt(sec,key,dv,_T(EMU48_INI));
#define WriteString(sec,key,v) WritePrivateProfileString(sec,key,v,_T(EMU48_INI))
#define WriteInt(sec,key,v) WritePrivateProfileInt(sec,key,v,_T(EMU48_INI))
#define DelKey(sec,key) WritePrivateProfileString(sec,key,NULL,_T(EMU48_INI))
static BOOL WritePrivateProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue, LPCTSTR lpszFilename)
{
TCHAR s[16];
wsprintf(s,_T("%i"),nValue);
return WritePrivateProfileString(lpszSection, lpszEntry, s, lpszFilename);
}
#else
// registry handling
#if !defined REGISTRYKEY
#define REGISTRYKEY "Software\\Emu48"
#endif
#define ReadString(sec,key,dv,v,sv) GetRegistryString(sec,key,dv,v,sv)
#define ReadInt(sec,key,dv) GetRegistryInt(sec,key,dv)
#define WriteString(sec,key,v) WriteReg(sec,key,REG_SZ,(BYTE *) v,(lstrlen(v)+1) * sizeof(*v))
#define WriteInt(sec,key,v) WriteReg(sec,key,REG_DWORD,(BYTE *) &v,sizeof(int))
#define DelKey(sec,key) DelReg(sec,key)
static VOID ReadReg(LPCTSTR lpSubKey, LPCTSTR lpValueName, LPBYTE lpData, DWORD *pdwSize)
{
TCHAR lpKey[256] = _T(REGISTRYKEY) _T("\\");
DWORD retCode,dwType;
HKEY hKey;
lstrcat(lpKey, lpSubKey); // full registry key
retCode = RegOpenKeyEx(HKEY_CURRENT_USER,
lpKey,
0,
KEY_QUERY_VALUE,
&hKey);
if (retCode == ERROR_SUCCESS)
{
retCode = RegQueryValueEx(hKey,lpValueName,NULL,&dwType,lpData,pdwSize);
RegCloseKey(hKey);
}
if (retCode != ERROR_SUCCESS) // registry entry not found
*pdwSize = 0; // return zero size
return;
}
static BOOL WriteReg(LPCTSTR lpSubKey, LPCTSTR lpValueName, DWORD dwType, CONST BYTE *lpData, DWORD cbData)
{
TCHAR lpKey[256] = _T(REGISTRYKEY) _T("\\");
DWORD retCode;
HKEY hKey;
DWORD dwDisposition;
lstrcat(lpKey, lpSubKey); // full registry key
retCode = RegCreateKeyEx(HKEY_CURRENT_USER,
lpKey,
0,_T(""),
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hKey,
&dwDisposition);
_ASSERT(retCode == ERROR_SUCCESS);
RegSetValueEx(hKey,lpValueName,0,dwType,lpData,cbData);
RegCloseKey(hKey);
return retCode == ERROR_SUCCESS;
}
static BOOL DelReg(LPCTSTR lpSubKey, LPCTSTR lpValueName)
{
TCHAR lpKey[256] = _T(REGISTRYKEY) _T("\\");
DWORD retCode;
HKEY hKey;
lstrcat(lpKey, lpSubKey); // full registry key
retCode = RegOpenKeyEx(HKEY_CURRENT_USER,
lpKey,
0,
KEY_SET_VALUE,
&hKey);
if (retCode == ERROR_SUCCESS)
{
retCode = RegDeleteValue(hKey,lpValueName);
RegCloseKey(hKey);
}
return retCode == ERROR_SUCCESS;
}
static DWORD GetRegistryString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpDefault, LPTSTR lpData, DWORD dwSize)
{
// buffer size in bytes
DWORD dwBufSize = dwSize * sizeof(*lpData);
ReadReg(lpszSection,lpszEntry,(LPBYTE) lpData,&dwBufSize);
if (dwBufSize == 0)
{
lstrcpyn(lpData,lpDefault,dwSize);
dwSize = lstrlen(lpData);
}
else
{
dwSize = (dwBufSize / sizeof(*lpData)) - 1;
}
return dwSize;
}
static UINT GetRegistryInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nDefault)
{
UINT nValue;
DWORD dwSize = sizeof(nValue);
ReadReg(lpszSection,lpszEntry,(LPBYTE) &nValue,&dwSize);
return dwSize ? nValue : nDefault;
}
#endif
//################
//#
//# Public functions
//#
//################
VOID ReadSettings(VOID)
{
// Files
ReadString(_T("Files"),_T("Emu48Directory"),szCurrentDirectory,szEmuDirectory,ARRAYSIZEOF(szEmuDirectory));
ReadString(_T("Files"),_T("RomDirectory"),_T(""),szRomDirectory,ARRAYSIZEOF(szRomDirectory));
bAutoSave = ReadInt(_T("Files"),_T("AutoSave"),bAutoSave);
bAutoSaveOnExit = ReadInt(_T("Files"),_T("AutoSaveOnExit"),bAutoSaveOnExit);
bSaveDefConfirm = ReadInt(_T("Files"),_T("SaveDefaultConfirm"),bSaveDefConfirm);
bStartupBackup = ReadInt(_T("Files"),_T("StartupBackup"),bStartupBackup);
bLoadObjectWarning = ReadInt(_T("Files"),_T("LoadObjectWarning"),bLoadObjectWarning);
// Port2
bPort2IsShared = ReadInt(_T("Port2"),_T("IsShared"),bPort2IsShared);
ReadString(_T("Port2"),_T("Filename"),_T("SHARED.BIN"),szPort2Filename,ARRAYSIZEOF(szPort2Filename));
// KML
bAlwaysDisplayLog = ReadInt(_T("KML"),_T("AlwaysDisplayLog"),bAlwaysDisplayLog);
// Debugger
wInstrSize = ReadInt(_T("Debugger"),_T("LastInstrBufSize"),wInstrSize);
// Disassembler
disassembler_mode = ReadInt(_T("Disassembler"),_T("Mnemonics"),disassembler_mode);
disassembler_symb = ReadInt(_T("Disassembler"),_T("Symbolic"),disassembler_symb);
// Emulator
bShowTitle = ReadInt(_T("Emulator"),_T("ShowTitle"),bShowTitle);
bShowMenu = ReadInt(_T("Emulator"),_T("ShowMenu"),bShowMenu);
bAlwaysOnTop = ReadInt(_T("Emulator"),_T("AlwaysOnTop"),bAlwaysOnTop);
bActFollowsMouse = ReadInt(_T("Emulator"),_T("ActivationFollowsMouse"),bActFollowsMouse);
bClientWinMove = ReadInt(_T("Emulator"),_T("ClientWinMove"),bClientWinMove);
bSingleInstance = ReadInt(_T("Emulator"),_T("SingleInstance"),bSingleInstance);
bRealSpeed = ReadInt(_T("Emulator"),_T("RealSpeed"),bRealSpeed);
dwSXCycles = ReadInt(_T("Emulator"),_T("SXCycles"),dwSXCycles);
dwGXCycles = ReadInt(_T("Emulator"),_T("GXCycles"),dwGXCycles);
dwGPCycles = ReadInt(_T("Emulator"),_T("GPCycles"),dwGPCycles); // CdB for HP: add apples
dwG2Cycles = ReadInt(_T("Emulator"),_T("G2Cycles"),dwG2Cycles); // CdB for HP: add apples
dwKeyMinDelay = ReadInt(_T("Emulator"),_T("KeyMinDelay"),dwKeyMinDelay);
dwWakeupDelay = ReadInt(_T("Emulator"),_T("WakeupDelay"),dwWakeupDelay);
bGrayscale = ReadInt(_T("Emulator"),_T("Grayscale"),bGrayscale);
uWaveDevId = ReadInt(_T("Emulator"),_T("WaveDeviceId"),uWaveDevId);
dwWaveVol = ReadInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol);
dwWaveTime = ReadInt(_T("Emulator"),_T("WaveTime"),dwWaveTime);
// LowBat
bLowBatDisable = ReadInt(_T("LowBat"),_T("Disable"),bLowBatDisable);
// Macro
bMacroRealSpeed = ReadInt(_T("Macro"),_T("RealSpeed"),bMacroRealSpeed);
nMacroTimeout = ReadInt(_T("Macro"),_T("ReplayTimeout"),nMacroTimeout);
dwMacroMinDelay = ReadInt(_T("Macro"),_T("KeyMinDelay"),dwMacroMinDelay);
// IrPrinter
ReadString(_T("IrPrinter"),_T("Address"),szUdpServer,szUdpServer,ARRAYSIZEOF(szUdpServer));
wUdpPort = ReadInt(_T("IrPrinter"),_T("Port"),wUdpPort);
// Serial
ReadString(_T("Serial"),_T("Wire"),_T(NO_SERIAL),szSerialWire,ARRAYSIZEOF(szSerialWire));
ReadString(_T("Serial"),_T("Ir"),_T(NO_SERIAL),szSerialIr,ARRAYSIZEOF(szSerialIr));
// ROM
bRomWriteable = ReadInt(_T("ROM"),_T("Writeable"),bRomWriteable);
bWP = ReadInt(_T("ROM"),_T("WP#"),bWP);
return;
}
VOID WriteSettings(VOID)
{
// Files
WriteString(_T("Files"),_T("Emu48Directory"),szEmuDirectory);
WriteInt(_T("Files"),_T("AutoSave"),bAutoSave);
WriteInt(_T("Files"),_T("AutoSaveOnExit"),bAutoSaveOnExit);
WriteInt(_T("Files"),_T("SaveDefaultConfirm"),bSaveDefConfirm);
WriteInt(_T("Files"),_T("StartupBackup"),bStartupBackup);
WriteInt(_T("Files"),_T("LoadObjectWarning"),bLoadObjectWarning);
// Port2
WriteInt(_T("Port2"),_T("IsShared"),bPort2IsShared);
WriteString(_T("Port2"),_T("Filename"),szPort2Filename);
// KML
WriteInt(_T("KML"),_T("AlwaysDisplayLog"),bAlwaysDisplayLog);
// Debugger
WriteInt(_T("Debugger"),_T("LastInstrBufSize"),wInstrSize);
// Disassembler
WriteInt(_T("Disassembler"),_T("Mnemonics"),disassembler_mode);
WriteInt(_T("Disassembler"),_T("Symbolic"),disassembler_symb);
// Emulator
WriteInt(_T("Emulator"),_T("ShowTitle"),bShowTitle);
WriteInt(_T("Emulator"),_T("ShowMenu"),bShowMenu);
WriteInt(_T("Emulator"),_T("AlwaysOnTop"),bAlwaysOnTop);
WriteInt(_T("Emulator"),_T("ActivationFollowsMouse"),bActFollowsMouse);
WriteInt(_T("Emulator"),_T("ClientWinMove"),bClientWinMove);
WriteInt(_T("Emulator"),_T("SingleInstance"),bSingleInstance);
WriteInt(_T("Emulator"),_T("RealSpeed"),bRealSpeed);
WriteInt(_T("Emulator"),_T("SXCycles"),dwSXCycles);
WriteInt(_T("Emulator"),_T("GXCycles"),dwGXCycles);
WriteInt(_T("Emulator"),_T("GPCycles"),dwGPCycles); // CdB for HP: add apples
WriteInt(_T("Emulator"),_T("G2Cycles"),dwG2Cycles); // CdB for HP: add apples
WriteInt(_T("Emulator"),_T("KeyMinDelay"),dwKeyMinDelay);
WriteInt(_T("Emulator"),_T("WakeupDelay"),dwWakeupDelay);
WriteInt(_T("Emulator"),_T("Grayscale"),bGrayscale);
WriteInt(_T("Emulator"),_T("WaveDeviceId"),uWaveDevId);
WriteInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol);
WriteInt(_T("Emulator"),_T("WaveTime"),dwWaveTime);
// LowBat
WriteInt(_T("LowBat"),_T("Disable"),bLowBatDisable);
// Macro
WriteInt(_T("Macro"),_T("RealSpeed"),bMacroRealSpeed);
WriteInt(_T("Macro"),_T("ReplayTimeout"),nMacroTimeout);
WriteInt(_T("Macro"),_T("KeyMinDelay"),dwMacroMinDelay);
// IrPrinter
WriteString(_T("IrPrinter"),_T("Address"),szUdpServer);
WriteInt(_T("IrPrinter"),_T("Port"),wUdpPort);
// Serial
WriteString(_T("Serial"),_T("Wire"),szSerialWire);
WriteString(_T("Serial"),_T("Ir"),szSerialIr);
// ROM
WriteInt(_T("ROM"),_T("Writeable"),bRomWriteable);
return;
}
VOID ReadLastDocument(LPTSTR szFilename, DWORD nSize)
{
ReadString(_T("Files"),_T("LastDocument"),_T(""),szFilename,nSize);
return;
}
VOID WriteLastDocument(LPCTSTR szFilename)
{
WriteString(_T("Files"),_T("LastDocument"),szFilename);
return;
}
VOID ReadSettingsString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpDefault, LPTSTR lpData, DWORD dwSize)
{
ReadString(lpszSection,lpszEntry,lpDefault,lpData,dwSize);
return;
}
VOID WriteSettingsString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPTSTR lpData)
{
WriteString(lpszSection,lpszEntry,lpData);
return;
}
INT ReadSettingsInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nDefault)
{
return ReadInt(lpszSection,lpszEntry,nDefault);
}
VOID WriteSettingsInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nValue)
{
WriteInt(lpszSection,lpszEntry,nValue);
return;
}
VOID DelSettingsKey(LPCTSTR lpszSection, LPCTSTR lpszEntry)
{
DelKey(lpszSection,lpszEntry);
return;
}

102
app/src/main/cpp/SNDDEF.H Normal file
View file

@ -0,0 +1,102 @@
/*
* snddef.h
*
* This file is part of Emu48
*
* Copyright (C) 2015 Christoph Gießelink
*
*/
#include <initguid.h>
#if _MSC_VER >= 1600 // valid for VS2010 and later
#include <DSound.h>
#include <Dsconf.h>
#else // create the necessary definitions manually
//
// IKsPropertySet
//
#ifndef _IKsPropertySet_
#define _IKsPropertySet_
#ifdef __cplusplus
struct IKsPropertySet;
#endif // __cplusplus
typedef struct IKsPropertySet *LPKSPROPERTYSET;
DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93);
#undef INTERFACE
#define INTERFACE IKsPropertySet
DECLARE_INTERFACE_(IKsPropertySet, IUnknown)
{
// IUnknown methods
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID*) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
// IKsPropertySet methods
STDMETHOD(Get) (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength,
LPVOID pPropertyData, ULONG ulDataLength, PULONG pulBytesReturned) PURE;
STDMETHOD(Set) (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength,
LPVOID pPropertyData, ULONG ulDataLength) PURE;
STDMETHOD(QuerySupport) (THIS_ REFGUID rguidPropSet, ULONG ulId, PULONG pulTypeSupport) PURE;
};
#endif // _IKsPropertySet_
// DirectSound Configuration Component GUID {11AB3EC0-25EC-11d1-A4D8-00C04FC28ACA}
DEFINE_GUID(CLSID_DirectSoundPrivate, 0x11ab3ec0, 0x25ec, 0x11d1, 0xa4, 0xd8, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca);
// DirectSound Device Properties {84624F82-25EC-11d1-A4D8-00C04FC28ACA}
DEFINE_GUID(DSPROPSETID_DirectSoundDevice, 0x84624f82, 0x25ec, 0x11d1, 0xa4, 0xd8, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca);
typedef enum
{
DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A = 1,
DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1 = 2,
DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1 = 3,
DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W = 4,
DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A = 5,
DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W = 6,
DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A = 7,
DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W = 8,
} DSPROPERTY_DIRECTSOUNDDEVICE;
#ifdef UNICODE
#define DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W
#else // UNICODE
#define DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A
#endif // UNICODE
typedef enum
{
DIRECTSOUNDDEVICE_TYPE_EMULATED,
DIRECTSOUNDDEVICE_TYPE_VXD,
DIRECTSOUNDDEVICE_TYPE_WDM
} DIRECTSOUNDDEVICE_TYPE;
typedef enum
{
DIRECTSOUNDDEVICE_DATAFLOW_RENDER,
DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE
} DIRECTSOUNDDEVICE_DATAFLOW;
typedef struct _DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA
{
DIRECTSOUNDDEVICE_TYPE Type; // Device type
DIRECTSOUNDDEVICE_DATAFLOW DataFlow; // Device dataflow
GUID DeviceId; // DirectSound device id
LPTSTR Description; // Device description
LPTSTR Module; // Device driver module
LPTSTR Interface; // Device interface
ULONG WaveDeviceId; // Wave device id
} DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA, *PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA;
#endif

256
app/src/main/cpp/SNDENUM.C Normal file
View file

@ -0,0 +1,256 @@
/*
* SndEnum.c
*
* This file is part of Emu48
*
* Copyright (C) 2015 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
#include "snddef.h"
typedef HRESULT (WINAPI *LPFNDLLGETCLASSOBJECT)(REFCLSID,REFIID,LPVOID *);
static LPFNDLLGETCLASSOBJECT pfnDllGetClassObject = NULL;
//
// create a IKsPropertySet interface
//
static __inline HRESULT DirectSoundPrivateCreate(LPKSPROPERTYSET *ppKsPropertySet)
{
LPCLASSFACTORY pClassFactory = NULL;
HRESULT hr;
// create a class factory object
#if defined __cplusplus
hr = pfnDllGetClassObject(CLSID_DirectSoundPrivate,IID_IClassFactory,(LPVOID *) &pClassFactory);
#else
hr = pfnDllGetClassObject(&CLSID_DirectSoundPrivate,&IID_IClassFactory,(LPVOID *) &pClassFactory);
#endif
// create the DirectSoundPrivate object and query for an IKsPropertySet interface
if (SUCCEEDED(hr))
{
#if defined __cplusplus
hr = pClassFactory->CreateInstance(NULL,IID_IKsPropertySet,(LPVOID *) ppKsPropertySet);
#else
hr = pClassFactory->lpVtbl->CreateInstance(pClassFactory,NULL,&IID_IKsPropertySet,(LPVOID *) ppKsPropertySet);
#endif
}
if (pClassFactory) // release the class factory object
{
#if defined __cplusplus
pClassFactory->Release();
#else
pClassFactory->lpVtbl->Release(pClassFactory);
#endif
}
if (FAILED(hr) && *ppKsPropertySet) // handle failure
{
#if defined __cplusplus
(*ppKsPropertySet)->Release();
#else
(*ppKsPropertySet)->lpVtbl->Release(*ppKsPropertySet);
#endif
}
return hr;
}
//
// get the device information about a DirectSound GUID.
//
static BOOL GetInfoFromDSoundGUID(CONST GUID *lpGUID, UINT *puWaveDeviceID)
{
LPKSPROPERTYSET pKsPropertySet = NULL;
HRESULT hr;
BOOL bSuccess = FALSE;
hr = DirectSoundPrivateCreate(&pKsPropertySet);
if (SUCCEEDED(hr))
{
ULONG ulBytesReturned = 0;
DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA sDirectSoundDeviceDescription;
ZeroMemory(&sDirectSoundDeviceDescription,sizeof(sDirectSoundDeviceDescription));
sDirectSoundDeviceDescription.DeviceId = *lpGUID;
// get the size of the direct sound device description
#if defined __cplusplus
hr = pKsPropertySet->Get(
DSPROPSETID_DirectSoundDevice,
DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION,
NULL,
0,
&sDirectSoundDeviceDescription,
sizeof(sDirectSoundDeviceDescription),
&ulBytesReturned
);
#else
hr = pKsPropertySet->lpVtbl->Get(pKsPropertySet,
&DSPROPSETID_DirectSoundDevice,
DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION,
NULL,
0,
&sDirectSoundDeviceDescription,
sizeof(sDirectSoundDeviceDescription),
&ulBytesReturned
);
#endif
if (SUCCEEDED(hr) && ulBytesReturned)
{
PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA psDirectSoundDeviceDescription = NULL;
// fetch the direct sound device description
psDirectSoundDeviceDescription = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA) malloc(ulBytesReturned);
if (psDirectSoundDeviceDescription != NULL)
{
// init structure with data from length request
*psDirectSoundDeviceDescription = sDirectSoundDeviceDescription;
#if defined __cplusplus
hr = pKsPropertySet->Get(
DSPROPSETID_DirectSoundDevice,
DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION,
NULL,
0,
psDirectSoundDeviceDescription,
ulBytesReturned,
&ulBytesReturned
);
#else
hr = pKsPropertySet->lpVtbl->Get(pKsPropertySet,
&DSPROPSETID_DirectSoundDevice,
DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION,
NULL,
0,
psDirectSoundDeviceDescription,
ulBytesReturned,
&ulBytesReturned
);
#endif
if ((bSuccess = SUCCEEDED(hr)))
{
// the requested device ID
*puWaveDeviceID = psDirectSoundDeviceDescription->WaveDeviceId;
}
free(psDirectSoundDeviceDescription);
}
}
#if defined __cplusplus
pKsPropertySet->Release();
#else
pKsPropertySet->lpVtbl->Release(pKsPropertySet);
#endif
}
return bSuccess;
}
//
// callback function for DirectSoundEnumerate()
//
static BOOL CALLBACK DSEnumProc(LPGUID lpGUID,LPCTSTR lpszDesc,LPCTSTR lpszDrvName,LPVOID lpContext)
{
HWND hWnd = (HWND) lpContext; // window handle of the combo box
if (lpGUID != NULL) // NULL only for "Primary Sound Driver"
{
UINT uDevID;
if (GetInfoFromDSoundGUID(lpGUID,&uDevID))
{
WAVEOUTCAPS woc;
// has device the necessary capabilities?
if ( waveOutGetDevCaps(uDevID,&woc,sizeof(woc)) == MMSYSERR_NOERROR
&& (woc.dwFormats & WAVE_FORMAT_4M08) != 0)
{
// copy product name and wave device ID to combo box
LONG i = (LONG) SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) lpszDesc);
SendMessage(hWnd,CB_SETITEMDATA,i,uDevID);
}
}
}
return TRUE;
UNREFERENCED_PARAMETER(lpszDrvName);
}
// set listfield for sound device combo box
VOID SetSoundDeviceList(HWND hWnd,UINT uDeviceID)
{
typedef BOOL (CALLBACK *LPDSENUMCALLBACK)(LPGUID, LPCTSTR, LPCTSTR, LPVOID);
typedef HRESULT (WINAPI *LPFN_SDE)(LPDSENUMCALLBACK lpDSEnumCallback,LPVOID lpContext);
LPFN_SDE pfnDirectSoundEnumerate = NULL;
UINT uSelectDevice,uDevID,uDevNo;
HMODULE hDSound = LoadLibrary(_T("dsound.dll"));
if (hDSound != NULL) // direct sound dll found
{
#if defined _UNICODE
pfnDirectSoundEnumerate = (LPFN_SDE) GetProcAddress(hDSound,"DirectSoundEnumerateW");
#else
pfnDirectSoundEnumerate = (LPFN_SDE) GetProcAddress(hDSound,"DirectSoundEnumerateA");
#endif
pfnDllGetClassObject = (LPFNDLLGETCLASSOBJECT) GetProcAddress(hDSound,"DllGetClassObject");
}
SendMessage(hWnd,CB_RESETCONTENT,0,0);
// preset selector
uSelectDevice = (UINT) SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) _T("Standard Audio"));
SendMessage(hWnd,CB_SETITEMDATA,uSelectDevice,WAVE_MAPPER);
// check for direct sound interface functions
if (pfnDirectSoundEnumerate != NULL && pfnDllGetClassObject != NULL)
{
// copy product name and wave device ID to combo box
if (SUCCEEDED(pfnDirectSoundEnumerate((LPDSENUMCALLBACK) DSEnumProc,hWnd)))
{
UINT i;
uDevNo = (UINT) SendMessage(hWnd,CB_GETCOUNT,0,0);
for (i = 0; i < uDevNo; ++i)
{
// translate device ID to combo box position
uDevID = (UINT) SendMessage(hWnd,CB_GETITEMDATA,i,0);
if (uDevID == uDeviceID) uSelectDevice = i;
}
}
}
else // direct sound not available, detect over wave capabilities
{
WAVEOUTCAPS woc;
uDevNo = waveOutGetNumDevs();
for (uDevID = 0; uDevID < uDevNo; ++uDevID)
{
if ( waveOutGetDevCaps(uDevID,&woc,sizeof(woc)) == MMSYSERR_NOERROR
&& (woc.dwFormats & WAVE_FORMAT_4M08) != 0)
{
// copy product name and wave device ID to combo box
LONG i = (LONG) SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) woc.szPname);
SendMessage(hWnd,CB_SETITEMDATA,i,uDevID);
if (uDevID == uDeviceID) uSelectDevice = i;
}
}
}
// activate last selected combo box item
SendMessage(hWnd,CB_SETCURSEL,uSelectDevice,0L);
if (hDSound != NULL) // direct sound dll loaded
{
pfnDllGetClassObject = NULL;
VERIFY(FreeLibrary(hDSound));
}
return;
}

557
app/src/main/cpp/SOUND.C Normal file
View file

@ -0,0 +1,557 @@
/*
* sound.c
*
* This file is part of Emu48
*
* Copyright (C) 2013 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
// #define DEBUG_SOUND // switch for sound debug purpose
// #define SINE_APPROX // sine signal approximation
#define SAMPLES_PER_SEC 44100 // sound sampling rate
#define MILLISEC_PER_BUFFER 20 // time period of each sound buffer
#define NO_OF_BUFFERS 3 // number of reserve buffers before playing
typedef struct _MSAMPLE
{
LPBYTE pbyData;
DWORD dwBufferLength;
DWORD dwPosition;
// buffer admin part
DWORD dwIndex; // index to count no. of sample buffers
struct _MSAMPLE* pNext; // pointer to next sample buffer
} MSAMPLE, *PMSAMPLE;
DWORD dwWaveVol = 64; // wave sound volume
DWORD dwWaveTime = MILLISEC_PER_BUFFER; // time period (in ms) of each sound buffer
static HWAVEOUT hWaveDevice = NULL; // handle to the waveform-audio output device
static HANDLE hThreadWave = NULL; // thread handle of sound message handler
static DWORD dwThreadWaveId = 0; // thread id of sound message handler
static UINT uHeaders = 0; // no. of sending wave headers
static PMSAMPLE psHead = NULL; // head of sound samples
static PMSAMPLE psTail = NULL; // tail of sound samples
static CRITICAL_SECTION csSoundLock; // critical section for sound emulation
static DWORD dwSoundBufferLength; // sound buffer length for the given time period
static VOID FlushSample(VOID);
//
// sound message handler thread
//
static DWORD WINAPI SoundWndProc(LPVOID pParam)
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
if (msg.message == MM_WOM_DONE)
{
HWAVEOUT hwo = (HWAVEOUT) msg.wParam;
PWAVEHDR pwh = (PWAVEHDR) msg.lParam;
VERIFY(waveOutUnprepareHeader(hwo,pwh,sizeof(*pwh)) == MMSYSERR_NOERROR);
free(pwh->lpData); // free waveform data
free(pwh); // free wavefom header
_ASSERT(uHeaders > 0);
--uHeaders; // finished header
FlushSample(); // check for new sample
if (uHeaders == 0) // no wave headers in transmission
{
bSoundSlow = FALSE; // no sound slow down
bEnableSlow = TRUE; // reenable CPU slow down possibility
}
}
}
return 0;
UNREFERENCED_PARAMETER(pParam);
}
//
// create sound message handler thread
//
static BOOL CreateWaveThread(VOID)
{
_ASSERT(hThreadWave == NULL);
// create sound message handler thread
hThreadWave = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&SoundWndProc,NULL,0,&dwThreadWaveId);
return hThreadWave != NULL;
}
//
// destroy sound message handler thread
//
static VOID DestroyWaveThread(VOID)
{
if (hThreadWave != NULL) // sound message handler thread running
{
// shut down thread
while (!PostThreadMessage(dwThreadWaveId,WM_QUIT,0,0))
Sleep(0);
WaitForSingleObject(hThreadWave,INFINITE);
CloseHandle(hThreadWave);
hThreadWave = NULL;
}
return;
}
//
// add sample buffer to tail of sample job list
//
static __inline VOID AddSoundBuf(PMSAMPLE psData)
{
_ASSERT(psData != NULL); // there must be a sample
psData->pNext = NULL; // last sample in job list
// add sample to list
EnterCriticalSection(&csSoundLock);
{
if (psTail == NULL) // root
{
psData->dwIndex = 0; // this is the root index
_ASSERT(psHead == NULL);
psHead = psTail = psData; // add sample at head
}
else // add at tail
{
// use next index
psData->dwIndex = psTail->dwIndex + 1;
psTail->pNext = psData; // add sample at tail
psTail = psData;
}
}
LeaveCriticalSection(&csSoundLock);
return;
}
//
// remove sample buffer from head of sample job list
//
static __inline BOOL GetSoundBuf(PMSAMPLE *ppsData)
{
BOOL bSucc;
EnterCriticalSection(&csSoundLock);
{
if ((bSucc = (psHead != NULL))) // data in head
{
*ppsData = psHead; // get sample
psHead = psHead->pNext; // and remove it from head
if (psHead == NULL) // was last one in head
{
psTail = NULL; // so tail is also the last one
}
}
}
LeaveCriticalSection(&csSoundLock);
return bSucc;
}
//
// number of sample buffers in sample job list
//
static DWORD GetSoundBufSize(VOID)
{
DWORD dwNoSamples;
EnterCriticalSection(&csSoundLock);
{
// no. of samples in buffer
dwNoSamples = (psTail == NULL)
? 0
: (psTail->dwIndex - psHead->dwIndex) + 1;
}
LeaveCriticalSection(&csSoundLock);
return dwNoSamples;
}
//
// allocate new sample buffer and add the
// buffer to the tail of the sample job list
//
static __inline BOOL AllocSample(PMSAMPLE *ppsData)
{
// alloc new sample buffer
*ppsData = (PMSAMPLE) malloc(sizeof(**ppsData));
if (*ppsData != NULL)
{
(*ppsData)->dwPosition = 0; // begin of buffer
(*ppsData)->dwBufferLength = dwSoundBufferLength;
(*ppsData)->pbyData = (LPBYTE) malloc((*ppsData)->dwBufferLength);
if ((*ppsData)->pbyData != NULL)
{
// buffers allocated
_ASSERT(*ppsData != NULL && (*ppsData)->pbyData != NULL);
AddSoundBuf(*ppsData); // add sample buffer to list
}
else
{
free(*ppsData); // data alloc failed, delete sample buffer
*ppsData = NULL;
}
}
return *ppsData != NULL;
}
//
// write samples to sample buffer
//
static BOOL AddSamples(DWORD dwSamples, BYTE byLevel)
{
PMSAMPLE psData;
DWORD dwBufSamples;
#if defined SINE_APPROX
INT w,s,ss,x,y;
#endif
BOOL bSucc = TRUE;
if (dwSamples == 0) return TRUE; // nothing to add
#if defined SINE_APPROX
// calculate constants
w = (INT) (byLevel - 0x80); // max. wave level
s = (INT) dwSamples; // interval length (pi)
ss = s * s; // interval length ^ 2
x = 1; // sample no.
#endif
EnterCriticalSection(&csSoundLock);
{
psData = psTail; // get last sample buffer
do
{
// number of free sound samples in current buffer
dwBufSamples = (psData != NULL)
? (psData->dwBufferLength - psData->dwPosition)
: 0;
if (dwBufSamples == 0) // sample buffer is full
{
// alloc new sample buffer
VERIFY(bSucc = AllocSample(&psData));
if (!bSucc) break;
_ASSERT( psData != NULL
&& psData->pbyData != NULL
&& psData->dwPosition == 0);
dwBufSamples = psData->dwBufferLength;
}
if (dwSamples < dwBufSamples) // free sample buffer is larger then needed
dwBufSamples = dwSamples; // fill only the necessary no. of samples
dwSamples -= dwBufSamples; // remaining samples after buffer fill
// fill buffer with level for beep
#if defined SINE_APPROX
for (; dwBufSamples > 0; --dwBufSamples)
{
// sine approximation function
y = w - w * (4 * x * (x - s) + ss ) / ss;
++x; // next sample
psData->pbyData[psData->dwPosition++] = (BYTE) (y + 0x80);
}
#else
FillMemory(&psData->pbyData[psData->dwPosition],dwBufSamples,byLevel);
psData->dwPosition += dwBufSamples;
#endif
}
while (dwSamples > 0);
}
LeaveCriticalSection(&csSoundLock);
return bSucc;
}
//
// write sample buffer from head of sample job list
// to waveform-audio output device and delete the
// sample buffer control from head of sample job list
//
static VOID FlushSample(VOID)
{
PMSAMPLE psData;
_ASSERT(hWaveDevice != NULL);
if (GetSoundBuf(&psData) == TRUE) // fetch sample buffer
{
PWAVEHDR pwh;
// allocate new wave header
if ((pwh = (PWAVEHDR) malloc(sizeof(*pwh))) != NULL)
{
pwh->lpData = (LPSTR) psData->pbyData;
pwh->dwBufferLength = psData->dwPosition;
pwh->dwBytesRecorded = 0;
pwh->dwUser = 0;
pwh->dwFlags = 0;
pwh->dwLoops = 0;
++uHeaders; // add header
// prepare sample
VERIFY(waveOutPrepareHeader(hWaveDevice,pwh,sizeof(*pwh)) == MMSYSERR_NOERROR);
// send sample
VERIFY(waveOutWrite(hWaveDevice,pwh,sizeof(*pwh)) == MMSYSERR_NOERROR);
}
free(psData); // delete sample buffer
}
return;
}
//
// 44.1 kHz, mono, 8-bit waveform-audio output device available
//
BOOL SoundAvailable(UINT uDeviceID)
{
WAVEOUTCAPS woc;
return waveOutGetDevCaps(uDeviceID,&woc,sizeof(woc)) == MMSYSERR_NOERROR
&& (woc.dwFormats & WAVE_FORMAT_4M08) != 0;
}
//
// get the device ID of the current waveform-audio output device
//
BOOL SoundGetDeviceID(UINT *puDeviceID)
{
BOOL bSucc = FALSE;
if (hWaveDevice) // have sound device
{
bSucc = (waveOutGetID(hWaveDevice,puDeviceID) == MMSYSERR_NOERROR);
}
return bSucc;
}
//
// open waveform-audio output device
//
BOOL SoundOpen(UINT uDeviceID)
{
// check if sound device is already open
if (hWaveDevice == NULL && SoundAvailable(uDeviceID))
{
WAVEFORMATEX wf;
BOOL bSucc;
wf.wFormatTag = WAVE_FORMAT_PCM;
wf.nChannels = 1;
wf.nSamplesPerSec = SAMPLES_PER_SEC;
wf.wBitsPerSample = 8;
wf.nBlockAlign = wf.nChannels * wf.wBitsPerSample / 8;
wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec;
wf.cbSize = 0;
InitializeCriticalSection(&csSoundLock);
// sound buffer length for the given time period
dwSoundBufferLength = SAMPLES_PER_SEC * dwWaveTime / 1000;
if ((bSucc = CreateWaveThread())) // create sound message handler
{
// create a sound device, use the CALLBACK_THREAD flag because with the
// CALLBACK_FUNCTION flag unfortunately the called callback function
// can only call a specific set of Windows functions. Attempting to
// call other functions at the wrong time will result in a deadlock.
bSucc = (waveOutOpen(&hWaveDevice,uDeviceID,&wf,dwThreadWaveId,0,CALLBACK_THREAD) == MMSYSERR_NOERROR);
}
if (!bSucc)
{
DestroyWaveThread(); // shut down message thread
DeleteCriticalSection(&csSoundLock);
hWaveDevice = NULL;
}
}
return hWaveDevice != NULL;
}
//
// close waveform-audio output device
//
VOID SoundClose(VOID)
{
if (hWaveDevice != NULL)
{
EnterCriticalSection(&csSoundLock);
{
while (psHead != NULL) // cleanup remaining sample buffers
{
PMSAMPLE psNext = psHead->pNext;
free(psHead->pbyData);
free(psHead);
psHead = psNext;
}
psTail = NULL;
}
LeaveCriticalSection(&csSoundLock);
// abandon all pending wave headers
VERIFY(waveOutReset(hWaveDevice) == MMSYSERR_NOERROR);
DestroyWaveThread(); // shut down message thread
VERIFY(waveOutClose(hWaveDevice) == MMSYSERR_NOERROR);
DeleteCriticalSection(&csSoundLock);
hWaveDevice = NULL;
}
uHeaders = 0; // no wave headers in transmission
bSoundSlow = FALSE; // no sound slow down
bEnableSlow = TRUE; // reenable CPU slow down possibility
return;
}
//
// calculate the wave level from the beeper bit state
//
static BYTE WaveLevel(WORD wOut)
{
wOut >>= 11; // mask out beeper bit OR[11]
return (BYTE) (wOut & 0x01) + 1; // return 1 or 2
}
//
// decode change of beeper OUT bits
//
VOID SoundOut(CHIPSET* w, WORD wOut)
{
static DWORD dwLastCyc; // last timer value at beeper bit change
DWORD dwCycles,dwDiffSatCycles,dwDiffCycles,dwCpuFreq,dwSamples;
BYTE byWaveLevel;
// sound device not opened or waveform-audio output device not available
if (hWaveDevice == NULL)
return;
// actual timestamp
dwCycles = (DWORD) (w->cycles & 0xFFFFFFFF);
dwDiffSatCycles = dwCycles - dwLastCyc; // time difference from syncpoint in original Saturn cycles
// theoretical CPU frequency from given T2CYCLES
dwCpuFreq = T2CYCLES * 16384;
if (dwDiffSatCycles > dwCpuFreq / 2) // frequency < 1 Hz
{
dwLastCyc = dwCycles; // initial call for start beeping
return;
}
// estimated CPU cycles for Clarke/Yorke chip
dwDiffCycles = (cCurrentRomType == 'S')
? (dwDiffSatCycles * 26) / 25 // Clarke * 1.04
: (dwDiffSatCycles * 11) / 10; // Yorke * 1.10
// adjust original CPU cycles
w->cycles += (dwDiffCycles - dwDiffSatCycles);
dwLastCyc = (DWORD) (w->cycles & 0xFFFFFFFF); // new syncpoint
// calculate no. of sound samples from CPU cycles, !! intermediate result maybe > 32bit !!
dwSamples = (DWORD) ((2 * (QWORD) dwDiffCycles + 1) * SAMPLES_PER_SEC / 2 / dwCpuFreq);
if (dwSamples == 0) // frequency too high -> play nothing
return;
#if defined DEBUG_SOUND
{
TCHAR buffer[256];
// calculate rounded time in us
QWORD lDuration = 1000000 * (2 * (QWORD) dwDiffCycles + 1) / (2 * dwCpuFreq);
wsprintf(buffer,_T("State %u: Time = %I64u us f = %u Hz, Time = %I64u us f = %u Hz\n"),
wOut >> 11,lDuration,(DWORD) (1000000 / 2 / lDuration),
(QWORD) dwSamples * 1000000 / SAMPLES_PER_SEC,SAMPLES_PER_SEC / 2 / dwSamples);
OutputDebugString(buffer);
}
#endif
// begin of beep
if (uHeaders == 0 && GetSoundBufSize() == 0)
{
// use silence buffers to start output engine
AddSamples(dwSoundBufferLength * NO_OF_BUFFERS,0x80);
}
// offset for wave level
byWaveLevel = 0x80 + (BYTE) (dwWaveVol * (WaveLevel(wOut) - WaveLevel(w->out)) / 2);
AddSamples(dwSamples,byWaveLevel); // add samples to latest wave sample buffer
if (GetSoundBufSize() > NO_OF_BUFFERS) // have more than 3 wave sample buffers
{
FlushSample(); // send 2 of them
FlushSample();
}
// ran out of buffers -> disable CPU slow down
EnterCriticalSection(&csSlowLock);
{
InitAdjustSpeed(); // init variables if necessary
bEnableSlow = (GetSoundBufSize() > 1);
}
LeaveCriticalSection(&csSlowLock);
if (bSoundSlow == FALSE)
{
EnterCriticalSection(&csSlowLock);
{
InitAdjustSpeed(); // init variables if necessary
bSoundSlow = TRUE; // CPU slow down
}
LeaveCriticalSection(&csSlowLock);
}
return;
}
//
// beep with frequency (Hz) and duration (ms)
//
VOID SoundBeep(DWORD dwFrequency, DWORD dwDuration)
{
QWORD lPeriods;
DWORD dwSamples;
BYTE byLevel;
// waveform-audio output device opened and have frequency
if (hWaveDevice && dwFrequency > 0)
{
// samples for 1/2 of time period
dwSamples = SAMPLES_PER_SEC / 2 / dwFrequency;
// overall half periods
lPeriods = (QWORD) dwFrequency * dwDuration / 500;
while (lPeriods-- > 0) // create sample buffers
{
// signal level
byLevel = 0x80 + (BYTE) ((((DWORD) lPeriods & 1) * 2 - 1) * (dwWaveVol / 2));
AddSamples(dwSamples,byLevel); // add half period sample
}
while (GetSoundBufSize() > 0) // samples in job list
FlushSample(); // send sample buffer
}
Sleep(dwDuration);
return;
}

834
app/src/main/cpp/STACK.C Normal file
View file

@ -0,0 +1,834 @@
/*
* stack.c
*
* This file is part of Emu48
*
* Copyright (C) 2005 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
#include "io.h"
#define fnRadix 51 // fraction mark
#define fnApprox 105 // exact / approx. mode (HP49G)
#define DOINT 0x02614 // Precision Integer (HP49G)
#define DOREAL 0x02933 // Real
#define DOCMP 0x02977 // Complex
#define DOCSTR 0x02A2C // String
BOOL bDetectClpObject = TRUE; // try to detect clipboard object
//################
//#
//# Low level subroutines
//#
//################
static LPTSTR Trim(LPCTSTR cp)
{
LPCTSTR pcWs = _T(" \t\n\r"); // valid whitespace characters
LPTSTR pc;
DWORD dwFirst,dwLast;
dwLast = lstrlen(cp); // last position in string (EOS)
// trim leading and tailing whitespace characters
dwFirst = (DWORD) _tcsspn(cp,pcWs); // position of 1st non whitespace character
// search for position behind last non whitespace character
while (dwLast > dwFirst && _tcschr(pcWs,cp[dwLast-1]) != NULL)
--dwLast;
dwLast = 1 + dwLast - dwFirst; // calculate buffer length
if ((pc = (LPTSTR) malloc(dwLast * sizeof(*pc))) != NULL)
{
lstrcpyn(pc,&cp[dwFirst],dwLast); // copy relevant data + EOS
}
return pc;
}
static INT RPL_GetZInt(BYTE CONST *pbyNum,INT nIntLen,LPTSTR cp,INT nSize)
{
INT i = 0; // character counter
_ASSERT(nSize > 0); // target buffer size
if (nIntLen > 1) // has sign nibble
{
--nIntLen; // remove sign from digit length
// check for valid sign
_ASSERT(pbyNum[nIntLen] == 0 || pbyNum[nIntLen] == 9);
if (pbyNum[nIntLen] == 9) // negative number
{
*cp++ = _T('-'); // add sign
--nSize; // dec dest buffer size
++i; // wrote one character
}
}
if (nIntLen >= nSize) return 0; // dest buffer overflow
i += nIntLen; // adjust character counter
while (nIntLen-- > 0) // write all digits
{
// check for valid digit
_ASSERT(pbyNum[nIntLen] >= 0 && pbyNum[nIntLen] <= 9);
*cp++ = _T('0') + pbyNum[nIntLen]; // and write
}
*cp = 0; // set EOS
return i;
}
static __inline INT SetZInt(LPCTSTR cp,LPBYTE pbyNum,INT nSize)
{
BYTE bySign;
INT nStrLen,nNumSize;
_ASSERT(nSize > 0); // target buffer size
nStrLen = lstrlen(cp); // source string length
if ( nStrLen == 0 // empty string
// precisition integer contain only these numbers
|| _tcsspn(cp,_T("0123456789+-")) != (SIZE_T) nStrLen)
return 0;
bySign = (*cp != _T('-')) ? 0 : 9; // set sign nibble
if (*cp == _T('-') || *cp == _T('+')) // skip sign character
{
++cp;
--nStrLen;
}
if (nStrLen == 1 && *cp == _T('0')) // special code for zero
{
*pbyNum = 0; // zero data
return 1; // finish
}
// nStrLen = no. of digits without sign
if (nStrLen >= nSize) // destination buffer too small
return 0;
nNumSize = nStrLen + 1; // no. of written data
while (--nStrLen >= 0) // eval all digits
{
TCHAR c = cp[nStrLen];
// only '0' .. '9' are valid here
if (!((c >= _T('0')) || (c <= _T('9'))))
return 0;
c -= _T('0');
*pbyNum++ = (BYTE) c;
}
*pbyNum = bySign; // add sign
return nNumSize;
}
static INT RPL_SetZInt(LPCTSTR cp,LPBYTE pbyNum,INT nSize)
{
LPTSTR pszData;
INT s = 0;
if ((pszData = Trim(cp)) != NULL) // create a trimmed working copy of the string
{
s = SetZInt(pszData,pbyNum,nSize);
free(pszData);
}
return s;
}
static INT RPL_GetBcd(BYTE CONST *pbyNum,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPTSTR cp,INT nSize)
{
BYTE byNib;
LONG v,lExp;
BOOL bPflag,bExpflag;
INT i;
lExp = 0;
for (v = 1; nExpLen--; v *= 10) // fetch exponent
{
lExp += (LONG) *pbyNum++ * v; // calc. exponent
}
if (lExp > v / 2) lExp -= v; // negative exponent
lExp -= nMantLen - 1; // set decimal point to end of mantissa
i = 0; // first character
bPflag = FALSE; // show no decimal point
bExpflag = FALSE; // show no exponent
// scan mantissa
for (v = (LONG) nMantLen - 1; v >= 0 || bPflag; v--)
{
if (v >= 0L) // still mantissa digits left
byNib = *pbyNum++;
else
byNib = 0; // zero for negativ exponent
if (!i) // still delete zeros at end
{
if (byNib == 0 && lExp && v > 0) // delete zeros
{
lExp++; // adjust exponent
continue;
}
// TRUE at x.E
bExpflag = v + lExp >= nMantLen || lExp < -nMantLen;
bPflag = !bExpflag && v < -lExp; // decimal point flag at neg. exponent
}
// set decimal point
if ((bExpflag && v == 0) || (!lExp && i))
{
if (i >= nSize) return 0; // dest buffer overflow
cp[i++] = cDec; // write decimal point
if (v < 0) // no mantissa digits any more
{
if (i >= nSize) return 0; // dest buffer overflow
cp[i++] = _T('0'); // write heading zero
}
bPflag = FALSE; // finished with negativ exponents
}
if (v >= 0 || bPflag)
{
if (i >= nSize) return 0; // dest buffer overflow
cp[i++] = (TCHAR) byNib + _T('0'); // write character
}
lExp++; // next position
}
if (*pbyNum == 9) // negative number
{
if (i >= nSize) return 0; // dest buffer overflow
cp[i++] = _T('-'); // write sign
}
if (i >= nSize) return 0; // dest buffer overflow
cp[i] = 0; // set EOS
for (v = 0; v < (i / 2); v++) // reverse string
{
TCHAR cNib = cp[v]; // swap chars
cp[v] = cp[i-v-1];
cp[i-v-1] = cNib;
}
// write number with exponent
if (bExpflag)
{
if (i + 5 >= nSize) return 0; // dest buffer overflow
i += wsprintf(&cp[i],_T("E%d"),lExp-1);
}
return i;
}
static __inline INT SetBcd(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPBYTE pbyNum,INT nSize)
{
TCHAR cVc[] = _T(".0123456789eE+-");
BYTE byNum[80];
INT i,nIp,nDp,nMaxExp;
LONG lExp;
cVc[0] = cDec; // replace decimal char
if ( nMantLen + nExpLen >= nSize // destination buffer too small
|| !*cp // empty string
|| _tcsspn(cp,cVc) != (SIZE_T) lstrlen(cp) // real contain only these numbers
|| (SIZE_T) lstrlen(cp) >= ARRAYSIZEOF(byNum)) // ignore too long reals
return 0;
byNum[0] = (*cp != _T('-')) ? 0 : 9; // set sign nibble
if (*cp == _T('-') || *cp == _T('+')) // skip sign character
cp++;
// only '.', '0' .. '9' are valid here
if (!((*cp == cDec) || (*cp >= _T('0')) || (*cp <= _T('9'))))
return 0;
nIp = 0; // length of integer part
if (*cp != cDec) // no decimal point
{
// count integer part
while (*cp >= _T('0') && *cp <= _T('9'))
byNum[++nIp] = *cp++ - _T('0');
if (!nIp) return 0;
}
// only '.', 'E', 'e' or end are valid here
if (!(!*cp || (*cp == cDec) || (*cp == _T('E')) || (*cp == _T('e'))))
return 0;
nDp = 0; // length of decimal part
if (*cp == cDec) // decimal point
{
cp++; // skip '.'
// count decimal part
while (*cp >= _T('0') && *cp <= _T('9'))
byNum[nIp + ++nDp] = *cp++ - _T('0');
}
// count number of heading zeros in mantissa
for (i = 0; byNum[i+1] == 0 && i + 1 < nIp + nDp; ++i) { }
if (i > 0) // have to normalize
{
INT j;
nIp -= i; // for later ajust of exponent
for (j = 1; j <= nIp + nDp; ++j) // normalize mantissa
byNum[j] = byNum[j + i];
}
if (byNum[1] == 0) // number is 0
{
ZeroMemory(pbyNum,nMantLen + nExpLen + 1);
return nMantLen + nExpLen + 1;
}
for (i = nIp + nDp; i < nMantLen;) // fill rest of mantissa with 0
byNum[++i] = 0;
// must be 'E', 'e' or end
if (!(!*cp || (*cp == _T('E')) || (*cp == _T('e'))))
return 0;
lExp = 0;
if (*cp == _T('E') || *cp == _T('e'))
{
cp++; // skip 'E'
i = FALSE; // positive exponent
if (*cp == _T('-') || *cp == _T('+'))
{
i = (*cp++ == _T('-')); // adjust exponent sign
}
// exponent symbol must be followed by number
if (*cp < _T('0') || *cp > _T('9')) return 0;
while (*cp >= _T('0') && *cp <= _T('9'))
lExp = lExp * 10 + *cp++ - _T('0');
if (i) lExp = -lExp;
}
if (*cp != 0) return 0;
// adjust exponent value with exponent from normalized mantissa
lExp += nIp - 1;
// calculate max. posive exponent
for (nMaxExp = 5, i = 1; i < nExpLen; ++i)
nMaxExp *= 10;
// check range of exponent
if ((lExp < 0 && -lExp >= nMaxExp) || (lExp >= nMaxExp))
return 0;
if (lExp < 0) lExp += 2 * nMaxExp; // adjust negative offset
for (i = nExpLen; i > 0; --i) // convert number into digits
{
byNum[nMantLen + i] = (BYTE) (lExp % 10);
lExp /= 10;
}
// copy to target in reversed order
for (i = nMantLen + nExpLen; i >= 0; --i)
*pbyNum++ = byNum[i];
return nMantLen + nExpLen + 1;
}
static INT RPL_SetBcd(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPBYTE pbyNum,INT nSize)
{
LPTSTR pszData;
INT s = 0;
if ((pszData = Trim(cp)) != NULL) // create a trimmed working copy of the string
{
s = SetBcd(pszData,nMantLen,nExpLen,cDec,pbyNum,nSize);
free(pszData);
}
return s;
}
static INT RPL_GetComplex(BYTE CONST *pbyNum,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPTSTR cp,INT nSize)
{
INT nLen,nPos;
TCHAR cSep;
cSep = (cDec == _T('.')) // current separator
? _T(',') // radix mark '.' -> ',' separator
: _T(';'); // radix mark ',' -> ';' separator
nPos = 0; // write buffer position
if (nSize < 5) return 0; // target buffer to small
nSize -= 4; // reserved room for (,)\0
cp[nPos++] = _T('('); // start of complex number
// real part
nLen = RPL_GetBcd(pbyNum,nMantLen,nExpLen,cDec,&cp[1],nSize);
if (nLen == 0) return 0; // target buffer to small
_ASSERT(nLen <= nSize);
nPos += nLen; // actual buffer postion
nSize -= nLen; // remainder target buffer size
cp[nPos++] = cSep; // write of complex number seperator
// imaginary part
nLen = RPL_GetBcd(&pbyNum[16],nMantLen,nExpLen,cDec,&cp[nPos],nSize);
if (nLen == 0) return 0; // target buffer to small
nPos += nLen; // actual buffer postion
cp[nPos++] = _T(')'); // end of complex number
cp[nPos] = 0; // EOS
_ASSERT(lstrlen(cp) == nPos);
return nPos;
}
static INT RPL_SetComplex(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPBYTE pbyNum,INT nSize)
{
LPTSTR pcSep,pszData;
INT nLen;
TCHAR cSep;
nLen = 0; // read data length
cSep = (cDec == _T('.')) // current separator
? _T(',') // radix mark '.' -> ',' separator
: _T(';'); // radix mark ',' -> ';' separator
if ((pszData = Trim(cp)) != NULL) // create a trimmed working copy of the string
{
INT nStrLength = lstrlen(pszData); // string length
// complex number with brackets around
if ( nStrLength > 0
&& pszData[0] == _T('(')
&& pszData[nStrLength - 1] == _T(')'))
{
pszData[--nStrLength] = 0; // replace ')' with EOS
// search for number separator
if ((pcSep = _tcschr(pszData+1,cSep)) != NULL)
{
INT nLen1st;
*pcSep = 0; // set EOS for 1st substring
// decode 1st substring
nLen1st = RPL_SetBcd(pszData+1,nMantLen,nExpLen,cDec,&pbyNum[0],nSize);
if (nLen1st > 0)
{
// decode 2nd substring
nLen = RPL_SetBcd(pcSep+1,nMantLen,nExpLen,cDec,&pbyNum[nMantLen+nExpLen+1],nSize-nLen1st);
if (nLen > 0)
{
nLen += nLen1st; // complete Bcd length
}
}
}
}
free(pszData);
}
return nLen;
}
//################
//#
//# Object subroutines
//#
//################
static TCHAR GetRadix(VOID)
{
// get locale decimal point
// GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SDECIMAL,&cDecimal,1);
return RPL_GetSystemFlag(fnRadix) ? _T(',') : _T('.');
}
static INT DoInt(DWORD dwAddress,LPTSTR cp,INT nSize)
{
LPBYTE lpbyData;
INT nLength,nIntLen;
nIntLen = Read5(dwAddress) - 5; // no. of digits
if (nIntLen <= 0) return 0; // error in calculator object
nLength = 0;
if ((lpbyData = (LPBYTE) malloc(nIntLen)))
{
// get precisition integer object content and decode it
Npeek(lpbyData,dwAddress+5,nIntLen);
nLength = RPL_GetZInt(lpbyData,nIntLen,cp,nSize);
free(lpbyData);
}
return nLength;
}
static INT DoReal(DWORD dwAddress,LPTSTR cp,INT nSize)
{
BYTE byNumber[16];
// get real object content and decode it
Npeek(byNumber,dwAddress,ARRAYSIZEOF(byNumber));
return RPL_GetBcd(byNumber,12,3,GetRadix(),cp,nSize);
}
static INT DoComplex(DWORD dwAddress,LPTSTR cp,INT nSize)
{
BYTE byNumber[32];
// get complex object content and decode it
Npeek(byNumber,dwAddress,ARRAYSIZEOF(byNumber));
return RPL_GetComplex(byNumber,12,3,GetRadix(),cp,nSize);
}
//################
//#
//# Stack routines
//#
//################
//
// ID_STACK_COPY
//
LRESULT OnStackCopy(VOID) // copy data from stack
{
TCHAR cBuffer[128];
HANDLE hClipObj;
LPBYTE lpbyData;
DWORD dwAddress,dwObject,dwSize;
UINT uClipboardFormat;
_ASSERT(nState == SM_RUN); // emulator must be in RUN state
if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state
{
InfoMessage(_T("The emulator is busy."));
return 0;
}
_ASSERT(nState == SM_SLEEP);
if ((dwAddress = RPL_Pick(1)) == 0) // pick address of level1 object
{
MessageBeep(MB_OK); // error beep
goto error;
}
switch (dwObject = Read5(dwAddress)) // select object
{
case DOINT: // Precision Integer (HP49G)
case DOREAL: // real object
case DOCMP: // complex object
dwAddress += 5; // object content
switch (dwObject)
{
case DOINT: // Precision Integer (HP49G)
// get precision integer object content and decode it
dwSize = DoInt(dwAddress,cBuffer,ARRAYSIZEOF(cBuffer));
break;
case DOREAL: // real object
// get real object content and decode it
dwSize = DoReal(dwAddress,cBuffer,ARRAYSIZEOF(cBuffer));
break;
case DOCMP: // complex object
// get complex object content and decode it
dwSize = DoComplex(dwAddress,cBuffer,ARRAYSIZEOF(cBuffer));
break;
}
// calculate buffer size
dwSize = (dwSize + 1) * sizeof(*cBuffer);
// memory allocation for clipboard data
if ((hClipObj = GlobalAlloc(GMEM_MOVEABLE,dwSize)) == NULL)
goto error;
if ((lpbyData = (LPBYTE) GlobalLock(hClipObj)))
{
// copy data to memory
CopyMemory(lpbyData,cBuffer,dwSize);
GlobalUnlock(hClipObj); // unlock memory
}
#if defined _UNICODE
uClipboardFormat = CF_UNICODETEXT;
#else
uClipboardFormat = CF_TEXT;
#endif
break;
case DOCSTR: // string
dwAddress += 5; // address of string length
dwSize = (Read5(dwAddress) - 5) / 2; // length of string
// memory allocation for clipboard data
if ((hClipObj = GlobalAlloc(GMEM_MOVEABLE,dwSize + 1)) == NULL)
goto error;
if ((lpbyData = (LPBYTE) GlobalLock(hClipObj))) // lock memory
{
// copy data into clipboard buffer
for (dwAddress += 5;dwSize-- > 0;dwAddress += 2,++lpbyData)
*lpbyData = Read2(dwAddress);
*lpbyData = 0; // set EOS
GlobalUnlock(hClipObj); // unlock memory
}
uClipboardFormat = CF_TEXT; // always text
break;
default:
MessageBeep(MB_OK); // error beep
goto error;
}
if (OpenClipboard(hWnd))
{
if (EmptyClipboard())
SetClipboardData(uClipboardFormat,hClipObj);
else
GlobalFree(hClipObj);
CloseClipboard();
}
else // clipboard open failed
{
GlobalFree(hClipObj);
}
error:
SwitchToState(SM_RUN);
return 0;
}
//
// ID_STACK_PASTE
//
LRESULT OnStackPaste(VOID) // paste data to stack
{
#if defined _UNICODE
#define CF_TEXTFORMAT CF_UNICODETEXT
#else
#define CF_TEXTFORMAT CF_TEXT
#endif
HANDLE hClipObj;
BOOL bSuccess = FALSE;
// check if clipboard format is available
if (!IsClipboardFormatAvailable(CF_TEXTFORMAT))
{
MessageBeep(MB_OK); // error beep
return 0;
}
SuspendDebugger(); // suspend debugger
bDbgAutoStateCtrl = FALSE; // disable automatic debugger state control
// calculator off, turn on
if (!(Chipset.IORam[BITOFFSET]&DON))
{
KeyboardEvent(TRUE,0,0x8000);
Sleep(dwWakeupDelay);
KeyboardEvent(FALSE,0,0x8000);
// wait for sleep mode
while (Chipset.Shutdn == FALSE) Sleep(0);
}
_ASSERT(nState == SM_RUN); // emulator must be in RUN state
if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state
{
InfoMessage(_T("The emulator is busy."));
goto cancel;
}
_ASSERT(nState == SM_SLEEP);
if (OpenClipboard(hWnd))
{
if ((hClipObj = GetClipboardData(CF_TEXTFORMAT)))
{
LPCTSTR lpstrClipdata;
LPBYTE lpbyData;
if ((lpstrClipdata = (LPCTSTR) GlobalLock(hClipObj)))
{
BYTE byNumber[128];
DWORD dwAddress;
INT s;
do
{
if (bDetectClpObject) // autodetect clipboard object enabled
{
// HP49G or HP49G+ in exact mode
if ( (cCurrentRomType == 'X' || cCurrentRomType == 'Q')
&& !RPL_GetSystemFlag(fnApprox))
{
// try to convert string to HP49 precision integer
s = RPL_SetZInt(lpstrClipdata,byNumber,sizeof(byNumber));
if (s > 0) // is a real number for exact mode
{
// get TEMPOB memory for HP49 precision integer object
dwAddress = RPL_CreateTemp(s+5+5,TRUE);
if ((bSuccess = (dwAddress > 0)))
{
Write5(dwAddress,DOINT); // prolog
Write5(dwAddress+5,s+5); // size
Nwrite(byNumber,dwAddress+10,s); // data
// push object to stack
RPL_Push(1,dwAddress);
}
break;
}
}
// try to convert string to real format
_ASSERT(16 <= ARRAYSIZEOF(byNumber));
s = RPL_SetBcd(lpstrClipdata,12,3,GetRadix(),byNumber,sizeof(byNumber));
if (s > 0) // is a real number
{
_ASSERT(s == 16); // length of real number BCD coded
// get TEMPOB memory for real object
dwAddress = RPL_CreateTemp(16+5,TRUE);
if ((bSuccess = (dwAddress > 0)))
{
Write5(dwAddress,DOREAL); // prolog
Nwrite(byNumber,dwAddress+5,s); // data
// push object to stack
RPL_Push(1,dwAddress);
}
break;
}
// try to convert string to complex format
_ASSERT(32 <= ARRAYSIZEOF(byNumber));
s = RPL_SetComplex(lpstrClipdata,12,3,GetRadix(),byNumber,sizeof(byNumber));
if (s > 0) // is a real complex
{
_ASSERT(s == 32); // length of complex number BCD coded
// get TEMPOB memory for complex object
dwAddress = RPL_CreateTemp(16+16+5,TRUE);
if ((bSuccess = (dwAddress > 0)))
{
Write5(dwAddress,DOCMP); // prolog
Nwrite(byNumber,dwAddress+5,s); // data
// push object to stack
RPL_Push(1,dwAddress);
}
break;
}
}
// any other format
{
DWORD dwSize = lstrlen(lpstrClipdata);
if ((lpbyData = (LPBYTE) malloc(dwSize * 2)))
{
LPBYTE lpbySrc,lpbyDest;
DWORD dwLoop;
#if defined _UNICODE
// copy data UNICODE -> ASCII
WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK,
lpstrClipdata, dwSize,
(LPSTR) lpbyData+dwSize, dwSize, NULL, NULL);
#else
// copy data
memcpy(lpbyData+dwSize,lpstrClipdata,dwSize);
#endif
// unpack data
lpbySrc = lpbyData+dwSize;
lpbyDest = lpbyData;
dwLoop = dwSize;
while (dwLoop-- > 0)
{
BYTE byTwoNibs = *lpbySrc++;
*lpbyDest++ = (BYTE) (byTwoNibs & 0xF);
*lpbyDest++ = (BYTE) (byTwoNibs >> 4);
}
dwSize *= 2; // size in nibbles
// get TEMPOB memory for string object
dwAddress = RPL_CreateTemp(dwSize+10,TRUE);
if ((bSuccess = (dwAddress > 0)))
{
Write5(dwAddress,DOCSTR); // String
Write5(dwAddress+5,dwSize+5); // length of String
Nwrite(lpbyData,dwAddress+10,dwSize); // data
// push object to stack
RPL_Push(1,dwAddress);
}
free(lpbyData);
}
}
}
while (FALSE);
GlobalUnlock(hClipObj);
}
}
CloseClipboard();
}
SwitchToState(SM_RUN); // run state
while (nState!=nNextState) Sleep(0);
_ASSERT(nState == SM_RUN);
if (bSuccess == FALSE) // data not copied
goto cancel;
KeyboardEvent(TRUE,0,0x8000);
Sleep(dwWakeupDelay);
KeyboardEvent(FALSE,0,0x8000);
// wait for sleep mode
while (Chipset.Shutdn == FALSE) Sleep(0);
cancel:
bDbgAutoStateCtrl = TRUE; // enable automatic debugger state control
ResumeDebugger();
return 0;
#undef CF_TEXTFORMAT
}

257
app/src/main/cpp/SYMBFILE.C Normal file
View file

@ -0,0 +1,257 @@
/*
* symbfile.c
*
* This file is part of Emu48
*
* Copyright (C) 2008 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
//################
//#
//# Saturn Object File Reading
//#
//################
#define RECORD_BLOCK 256 // block size
#define OS_RESOLVED 0x8000 // resolved symbol
#define OS_RELOCATABLE 0x4000 // relocatable symbol
#define SAT_ID "Saturn3" // saturn block header
#define SYMB_ID "Symb" // symbol block header
#define HASHENTRIES 199 // size of hash table
typedef struct _REFDATA
{
LPTSTR lpszName; // symbol name
DWORD dwAddr; // resolved address
struct _REFDATA* pNext;
} REFDATA, *PREFDATA;
static PREFDATA ppsBase[HASHENTRIES]; // base of symbol references (initialized with NULL)
static __inline DWORD GetHash(DWORD dwVal)
{
return dwVal % HASHENTRIES; // hash function
}
static DWORD GetBigEndian(LPBYTE pbyData, INT nSize)
{
DWORD dwVal = 0;
while (nSize-- > 0)
{
dwVal <<= 8;
dwVal += *pbyData++;
}
return dwVal;
}
//
// check if entry table is empty
//
BOOL RplTableEmpty(VOID)
{
DWORD i;
BOOL bEmpty = TRUE;
// check if hash table is empty
for (i = 0; bEmpty && i < ARRAYSIZEOF(ppsBase); ++i)
{
bEmpty = (ppsBase[i] == NULL); // check if empty
}
return bEmpty;
}
//
// load entry table
//
BOOL RplLoadTable(LPCTSTR lpszFilename)
{
BYTE byPage[RECORD_BLOCK]; // record page size
HANDLE hFile;
DWORD dwFileLength,dwCodeLength,dwNoSymbols,dwNoReferences;
DWORD dwFilePos,dwBytesRead,dwSymb,dwPageIndex,dwResolvedSymb;
BOOL bSymbol,bSucc;
bSucc = FALSE;
hFile = CreateFile(lpszFilename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
dwResolvedSymb = 0; // no resolved symbols added
bSymbol = TRUE; // next set is a symbol
// read first page
ReadFile(hFile,byPage,sizeof(byPage),&dwBytesRead,NULL);
if (dwBytesRead == sizeof(byPage) && memcmp(byPage,SAT_ID,7) == 0)
{
// file length in bytes
dwFileLength = GetBigEndian(byPage+7,sizeof(WORD)) * sizeof(byPage);
// code area in nibbles
dwCodeLength = GetBigEndian(byPage+9,sizeof(DWORD));
// no. of symbols & references
dwNoSymbols = GetBigEndian(byPage+13,sizeof(WORD));
// no. of references
dwNoReferences = GetBigEndian(byPage+15,sizeof(WORD));
// convert code area length into no. of pages
dwPageIndex = (dwCodeLength + (2 * sizeof(byPage) - 1)) / (2 * sizeof(byPage));
// calculate no. of code pages
dwFilePos = dwPageIndex * sizeof(byPage);
// jump to begin of symbols by skipping no. of code pages
bSucc = SetFilePointer(hFile,dwFilePos,NULL,FILE_CURRENT) != INVALID_SET_FILE_POINTER;
dwFilePos += sizeof(byPage); // actual file position
}
// read all symbol pages
for (dwPageIndex = 256, dwSymb = 0; bSucc && dwSymb < dwNoSymbols; dwPageIndex += 42)
{
if (dwPageIndex >= 256) // read complete page
{
// read new symbol page
ReadFile(hFile,byPage,sizeof(byPage),&dwBytesRead,NULL);
dwFilePos += dwBytesRead; // update file position
if ( dwFilePos > dwFileLength
|| dwBytesRead != sizeof(byPage)
|| memcmp(byPage,SYMB_ID,4) != 0)
{
bSucc = FALSE;
break;
}
dwPageIndex = 4; // begin of new symbol
}
if (bSymbol) // this is the 42 byte symbol set
{
WORD wSymbolType = (WORD) GetBigEndian(byPage+dwPageIndex+36,sizeof(WORD));
// check if it's a resolved or relocatable symbol
bSymbol = (wSymbolType & OS_RESOLVED) != 0;
if (bSymbol) ++dwResolvedSymb; // added resolved symbol
if (wSymbolType == OS_RESOLVED) // resolved symbol type
{
TCHAR szSymbolName[36+1],*pcPtr;
PREFDATA pData;
DWORD dwHash;
#if defined _UNICODE
{
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,(LPCSTR)byPage+dwPageIndex,36,
szSymbolName,ARRAYSIZEOF(szSymbolName));
szSymbolName[36] = 0; // set EOS
}
#else
{
lstrcpyn(szSymbolName,(LPCSTR)byPage+dwPageIndex,ARRAYSIZEOF(szSymbolName));
}
#endif
// cut symbol name at first space character
if ((pcPtr = _tcschr(szSymbolName,_T(' '))) != NULL)
*pcPtr = 0; // set EOS
// allocate symbol memory
VERIFY(pData = (PREFDATA) malloc(sizeof(*pData)));
pData->lpszName = DuplicateString(szSymbolName);
pData->dwAddr = GetBigEndian(byPage+dwPageIndex+38,sizeof(DWORD));
// add to hash table
dwHash = GetHash(pData->dwAddr);
pData->pNext = ppsBase[dwHash];
ppsBase[dwHash] = pData;
}
++dwSymb; // got symbol
}
else // 42 byte fill reference
{
bSymbol = TRUE; // nothing to do, next is a symbol set
}
}
bSucc = bSucc && (dwFilePos <= dwFileLength)
&& (dwNoSymbols == (dwResolvedSymb + dwNoReferences));
CloseHandle(hFile);
}
if (!bSucc) RplDeleteTable(); // delete current table
return bSucc;
}
//
// delete entry table
//
VOID RplDeleteTable(VOID)
{
PREFDATA pData;
DWORD i;
// clear hash entries
for (i = 0; i < ARRAYSIZEOF(ppsBase); ++i)
{
while (ppsBase[i] != NULL) // walk through all datasets
{
pData = ppsBase[i]->pNext;
free(ppsBase[i]->lpszName);
free(ppsBase[i]);
ppsBase[i] = pData;
}
}
return;
}
//
// return name for given entry address
//
LPCTSTR RplGetName(DWORD dwAddr)
{
PREFDATA pData = ppsBase[GetHash(dwAddr)];
// walk through all datasets of hash entry
for (; pData != NULL; pData = pData->pNext)
{
if (pData->dwAddr == dwAddr) // found address
return pData->lpszName; // return symbol name
}
return NULL;
}
//
// return entry address for given name
//
BOOL RplGetAddr(LPCTSTR lpszName, DWORD *pdwAddr)
{
PREFDATA pData;
DWORD i;
// check for every dataset in hash table
for (i = 0; i < ARRAYSIZEOF(ppsBase); ++i)
{
// walk through all datasets of hash entry
for (pData = ppsBase[i]; pData != NULL; pData = pData->pNext)
{
// found symbol name
if (lstrcmp(lpszName,pData->lpszName) == 0)
{
*pdwAddr = pData->dwAddr; // return address
return FALSE; // found
}
}
}
return TRUE; // not found
}

435
app/src/main/cpp/TIMER.C Normal file
View file

@ -0,0 +1,435 @@
/*
* timer.c
*
* This file is part of Emu48
*
* Copyright (C) 1995 Sebastien Carlier
*
*/
#include "pch.h"
#include "Emu48.h"
#include "ops.h"
#include "io.h" // I/O definitions
#define AUTO_OFF 10 // Time in minutes for 'auto off'
// Ticks for 'auto off'
#define OFF_TIME ((ULONGLONG) (AUTO_OFF * 60) << 13)
// memory address for clock and auto off
// S(X) = 0x70052-0x70070, G(X) = 0x80058-0x80076, 49G = 0x80058-0x80076
#define RPLTIME ((cCurrentRomType=='S')?0x52:0x58)
#define T1_FREQ 62 // Timer1 1/frequency in ms
#define T2_FREQ 8192 // Timer2 frequency
static BOOL bStarted = FALSE;
static BOOL bOutRange = FALSE; // flag if timer value out of range
static UINT uT1TimerId = 0;
static UINT uT2TimerId = 0;
static BOOL bNINT2T1 = FALSE; // state of NINT2 affected from timer1
static BOOL bNINT2T2 = FALSE; // state of NINT2 affected from timer2
static BOOL bAccurateTimer; // flag if accurate timer is used
static LARGE_INTEGER lT2Ref; // counter value at timer2 start
static TIMECAPS tc; // timer information
static UINT uT2MaxTicks; // max. timer2 ticks handled by one timer event
static DWORD dwT2Ref; // timer2 value at last timer2 access
static DWORD dwT2Cyc; // cpu cycle counter at last timer2 access
static void CALLBACK TimeProc(UINT uEventId, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2);
static DWORD CalcT2(VOID) // calculate timer2 value
{
DWORD dwT2 = Chipset.t2; // get value from chipset
if (bStarted) // timer2 running
{
LARGE_INTEGER lT2Act;
DWORD dwT2Dif;
// timer should run a little bit faster (10%) than maschine in authentic speed mode
DWORD dwCycPerTick = (9 * T2CYCLES) / 5;
QueryPerformanceCounter(&lT2Act); // actual time
// calculate realtime timer2 ticks since reference point
dwT2 -= (DWORD)
(((lT2Act.QuadPart - lT2Ref.QuadPart) * T2_FREQ)
/ lFreq.QuadPart);
dwT2Dif = dwT2Ref - dwT2; // timer2 ticks since last request
// checking if the MSB of dwT2Dif can be used as sign flag
_ASSERT((DWORD) tc.wPeriodMax < ((1<<(sizeof(dwT2Dif)*8-1))/8192)*1000);
// 2nd timer call in a 32ms time frame or elapsed time is negative (Win2k bug)
if (!Chipset.Shutdn && ((dwT2Dif > 0x01 && dwT2Dif <= 0x100) || (dwT2Dif & 0x80000000) != 0))
{
DWORD dwT2Ticks = ((DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwT2Cyc) / dwCycPerTick;
// estimated < real elapsed timer2 ticks or negative time
if (dwT2Ticks < dwT2Dif || (dwT2Dif & 0x80000000) != 0)
{
// real time too long or got negative time elapsed
dwT2 = dwT2Ref - dwT2Ticks; // estimated timer2 value from CPU cycles
dwT2Cyc += dwT2Ticks * dwCycPerTick; // estimated CPU cycles for the timer2 ticks
}
else
{
// reached actual time -> new synchronizing
dwT2Cyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwCycPerTick;
}
}
else
{
// valid actual time -> new synchronizing
dwT2Cyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwCycPerTick;
}
// check if timer2 interrupt is active -> no timer2 value below 0xFFFFFFFF
if ( Chipset.inte
&& (dwT2 & 0x80000000) != 0
&& (!Chipset.Shutdn || (Chipset.IORam[TIMER2_CTRL]&WKE))
&& (Chipset.IORam[TIMER2_CTRL]&INTR)
)
{
dwT2 = 0xFFFFFFFF;
dwT2Cyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwCycPerTick;
}
dwT2Ref = dwT2; // new reference time
}
return dwT2;
}
static VOID CheckT1(BYTE nT1)
{
// implementation of TSRQ
bNINT2T1 = (Chipset.IORam[TIMER1_CTRL]&INTR) != 0 && (nT1&8) != 0;
IOBit(SRQ1,TSRQ,bNINT2T1 || bNINT2T2);
if ((nT1&8) == 0) // timer1 MSB not set
{
Chipset.IORam[TIMER1_CTRL] &= ~SRQ; // clear SRQ bit
return;
}
_ASSERT((nT1&8) != 0); // timer1 MSB set
// timer MSB and INT or WAKE bit is set
if ((Chipset.IORam[TIMER1_CTRL]&(WKE|INTR)) != 0)
Chipset.IORam[TIMER1_CTRL] |= SRQ; // set SRQ
// cpu not sleeping and T1 -> Interrupt
if ( (!Chipset.Shutdn || (Chipset.IORam[TIMER1_CTRL]&WKE))
&& (Chipset.IORam[TIMER1_CTRL]&INTR))
{
Chipset.SoftInt = TRUE;
bInterrupt = TRUE;
}
// cpu sleeping and T1 -> Wake Up
if (Chipset.Shutdn && (Chipset.IORam[TIMER1_CTRL]&WKE))
{
Chipset.IORam[TIMER1_CTRL] &= ~WKE; // clear WKE bit
Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode
SetEvent(hEventShutdn); // wake up emulation thread
}
return;
}
static VOID CheckT2(DWORD dwT2)
{
// implementation of TSRQ
bNINT2T2 = (Chipset.IORam[TIMER2_CTRL]&INTR) != 0 && (dwT2&0x80000000) != 0;
IOBit(SRQ1,TSRQ,bNINT2T1 || bNINT2T2);
if ((dwT2&0x80000000) == 0) // timer2 MSB not set
{
Chipset.IORam[TIMER2_CTRL] &= ~SRQ; // clear SRQ bit
return;
}
_ASSERT((dwT2&0x80000000) != 0); // timer2 MSB set
// timer MSB and INT or WAKE bit is set
if ((Chipset.IORam[TIMER2_CTRL]&(WKE|INTR)) != 0)
Chipset.IORam[TIMER2_CTRL] |= SRQ; // set SRQ
// cpu not sleeping and T2 -> Interrupt
if ( (!Chipset.Shutdn || (Chipset.IORam[TIMER2_CTRL]&WKE))
&& (Chipset.IORam[TIMER2_CTRL]&INTR))
{
Chipset.SoftInt = TRUE;
bInterrupt = TRUE;
}
// cpu sleeping and T2 -> Wake Up
if (Chipset.Shutdn && (Chipset.IORam[TIMER2_CTRL]&WKE))
{
Chipset.IORam[TIMER2_CTRL] &= ~WKE; // clear WKE bit
Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode
SetEvent(hEventShutdn); // wake up emulation thread
}
return;
}
static VOID RescheduleT2(BOOL bRefPoint)
{
UINT uDelay;
_ASSERT(uT2TimerId == 0); // timer2 must stopped
if (bRefPoint) // save reference time
{
dwT2Ref = Chipset.t2; // timer2 value at last timer2 access
dwT2Cyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); // cpu cycle counter at last timer2 access
QueryPerformanceCounter(&lT2Ref); // time of corresponding Chipset.t2 value
uDelay = Chipset.t2; // timer value for delay
}
else // called without new refpoint, restart t2 with actual value
{
uDelay = CalcT2(); // actual timer value for delay
}
if ((bOutRange = uDelay > uT2MaxTicks)) // delay greater maximum delay
uDelay = uT2MaxTicks; // wait maximum delay time
uDelay = (uDelay * 125 + 1023) / 1024; // timer delay in ms (1000/8192 = 125/1024)
uDelay = __max(tc.wPeriodMin,uDelay); // wait minimum delay of timer
_ASSERT(uDelay <= tc.wPeriodMax); // inside maximum event delay
// start timer2; schedule event, when Chipset.t2 will be zero
VERIFY(uT2TimerId = timeSetEvent(uDelay,0,&TimeProc,2,TIME_ONESHOT));
return;
}
static VOID AbortT2(VOID)
{
_ASSERT(uT2TimerId);
timeKillEvent(uT2TimerId); // kill event
uT2TimerId = 0; // then reset var
return;
}
static void CALLBACK TimeProc(UINT uEventId, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
{
if (uEventId == 0) return; // illegal EventId
if (uEventId == uT1TimerId) // called from timer1 event (default period 16 Hz)
{
EnterCriticalSection(&csT1Lock);
{
Chipset.t1 = (Chipset.t1-1)&0xF;// decrement timer value
CheckT1(Chipset.t1); // test timer1 control bits
}
LeaveCriticalSection(&csT1Lock);
return;
}
if (uEventId == uT2TimerId) // called from timer2 event, Chipset.t2 should be zero
{
EnterCriticalSection(&csT2Lock);
{
uT2TimerId = 0; // single shot timer timer2 stopped
if (!bOutRange) // timer event elapsed
{
// timer2 overrun, test timer2 control bits else restart timer2
Chipset.t2 = CalcT2(); // calculate new timer2 value
CheckT2(Chipset.t2); // test timer2 control bits
}
RescheduleT2(!bOutRange); // restart timer2
}
LeaveCriticalSection(&csT2Lock);
return;
}
return;
UNREFERENCED_PARAMETER(uMsg);
UNREFERENCED_PARAMETER(dwUser);
UNREFERENCED_PARAMETER(dw1);
UNREFERENCED_PARAMETER(dw2);
}
VOID SetHP48Time(VOID) // set date and time
{
SYSTEMTIME ts;
ULONGLONG ticks, time;
DWORD dw;
WORD crc, i;
BYTE p[4];
_ASSERT(sizeof(ULONGLONG) == 8); // check size of datatype
GetLocalTime(&ts); // local time, _ftime() cause memory/resource leaks
// calculate days until 01.01.0000 (Erlang BIF localtime/0)
dw = (DWORD) ts.wMonth;
if (dw > 2)
dw -= 3L;
else
{
dw += 9L;
--ts.wYear;
}
dw = (DWORD) ts.wDay + (153L * dw + 2L) / 5L;
dw += (146097L * (((DWORD) ts.wYear) / 100L)) / 4L;
dw += (1461L * (((DWORD) ts.wYear) % 100L)) / 4L;
dw += (-719469L + 719528L); // days from year 0
ticks = (ULONGLONG) dw; // convert to 64 bit
// convert into seconds and add time
ticks = ticks * 24L + (ULONGLONG) ts.wHour;
ticks = ticks * 60L + (ULONGLONG) ts.wMinute;
ticks = ticks * 60L + (ULONGLONG) ts.wSecond;
// create timerticks = (s + ms) * 8192
ticks = (ticks << 13) | (((ULONGLONG) ts.wMilliseconds << 10) / 125);
ticks += Chipset.t2; // add actual timer2 value
time = ticks; // save for calc. timeout
time += OFF_TIME; // add 10 min for auto off
dw = RPLTIME; // HP addresses for clock in port0
crc = 0x0; // reset crc value
for (i = 0; i < 13; ++i, ++dw) // write date and time
{
*p = (BYTE) ticks & 0xf;
crc = (crc >> 4) ^ (((crc ^ ((WORD) *p)) & 0xf) * 0x1081);
Port0[dw] = *p; // always store in port0
ticks >>= 4;
}
Nunpack(p,crc,4); // write crc
memcpy(Port0+dw,p,4); // always store in port0
dw += 4; // HP addresses for timeout
for (i = 0; i < 13; ++i, ++dw) // write time for auto off
{
Port0[dw] = (BYTE) time & 0xf; // always store in port0
time >>= 4;
}
Port0[dw] = 0xf; // always store in port0
return;
}
VOID StartTimers(VOID)
{
if (bStarted) // timer running
return; // -> quit
if (Chipset.IORam[TIMER2_CTRL]&RUN) // start timer1 and timer2 ?
{
bStarted = TRUE; // flag timer running
// initialisation of NINT2 lines
bNINT2T1 = (Chipset.IORam[TIMER1_CTRL]&INTR) != 0 && (Chipset.t1 & 8) != 0;
bNINT2T2 = (Chipset.IORam[TIMER2_CTRL]&INTR) != 0 && (Chipset.t2 & 0x80000000) != 0;
timeGetDevCaps(&tc,sizeof(tc)); // get timer resolution
// max. timer2 ticks that can be handled by one timer event
uT2MaxTicks = __min((0xFFFFFFFF / 1024),tc.wPeriodMax);
uT2MaxTicks = __min((0xFFFFFFFF - 1023) / 125,uT2MaxTicks * 1024 / 125);
CheckT1(Chipset.t1); // check for timer1 interrupts
CheckT2(Chipset.t2); // check for timer2 interrupts
// set timer resolution to greatest possible one
bAccurateTimer = (timeBeginPeriod(tc.wPeriodMin) == TIMERR_NOERROR);
// set timer1 with given period
VERIFY(uT1TimerId = timeSetEvent(T1_FREQ,0,&TimeProc,1,TIME_PERIODIC));
RescheduleT2(TRUE); // start timer2
}
return;
}
VOID StopTimers(VOID)
{
if (!bStarted) // timer stopped
return; // -> quit
if (uT1TimerId != 0) // timer1 running
{
// Critical Section handler may cause a dead lock
timeKillEvent(uT1TimerId); // stop timer1
uT1TimerId = 0; // set flag timer1 stopped
}
if (uT2TimerId != 0) // timer2 running
{
EnterCriticalSection(&csT2Lock);
{
Chipset.t2 = CalcT2(); // update chipset timer2 value
}
LeaveCriticalSection(&csT2Lock);
AbortT2(); // stop timer2 outside critical section
}
bStarted = FALSE;
if (bAccurateTimer) // "Accurate timer" running
{
timeEndPeriod(tc.wPeriodMin); // finish service
}
return;
}
DWORD ReadT2(VOID)
{
DWORD dwT2;
EnterCriticalSection(&csT2Lock);
{
dwT2 = CalcT2(); // calculate timer2 value or if stopped last timer value
CheckT2(dwT2); // update timer2 control bits
}
LeaveCriticalSection(&csT2Lock);
return dwT2;
}
VOID SetT2(DWORD dwValue)
{
// calling AbortT2() inside Critical Section handler may cause a dead lock
if (uT2TimerId != 0) // timer2 running
AbortT2(); // stop timer2
EnterCriticalSection(&csT2Lock);
{
Chipset.t2 = dwValue; // set new value
CheckT2(Chipset.t2); // test timer2 control bits
if (bStarted) // timer running
RescheduleT2(TRUE); // restart timer2
}
LeaveCriticalSection(&csT2Lock);
return;
}
BYTE ReadT1(VOID)
{
BYTE nT1;
EnterCriticalSection(&csT1Lock);
{
nT1 = Chipset.t1; // read timer1 value
CheckT1(nT1); // update timer1 control bits
}
LeaveCriticalSection(&csT1Lock);
return nT1;
}
VOID SetT1(BYTE byValue)
{
BOOL bEqual;
_ASSERT(byValue < 0x10); // timer1 is only a 4bit counter
EnterCriticalSection(&csT1Lock);
{
bEqual = (Chipset.t1 == byValue); // check for same value
}
LeaveCriticalSection(&csT1Lock);
if (bEqual) return; // same value doesn't restart timer period
if (uT1TimerId != 0) // timer1 running
{
timeKillEvent(uT1TimerId); // stop timer1
uT1TimerId = 0; // set flag timer1 stopped
}
EnterCriticalSection(&csT1Lock);
{
Chipset.t1 = byValue; // set new timer1 value
CheckT1(Chipset.t1); // test timer1 control bits
}
LeaveCriticalSection(&csT1Lock);
if (bStarted) // timer running
{
// restart timer1 to get full period of frequency
VERIFY(uT1TimerId = timeSetEvent(T1_FREQ,0,&TimeProc,1,TIME_PERIODIC));
}
return;
}

124
app/src/main/cpp/TYPES.H Normal file
View file

@ -0,0 +1,124 @@
/*
* types.h
*
* This file is part of Emu48
*
* Copyright (C) 1995 Sebastien Carlier
*
*/
// HST bits
#define XM 1
#define SB 2
#define SR 4
#define MP 8
#define SWORD SHORT // signed 16 Bit variable
#define QWORD ULONGLONG // unsigned 64 Bit variable
#define CHIPSET Chipset_t
typedef struct
{
SWORD nPosX; // position of window
SWORD nPosY;
BYTE type; // calculator type
DWORD Port0Size; // real size of module in KB
DWORD Port1Size; // real size of module in KB
DWORD Port2Size; // real size of module in KB (HP49G only)
DWORD dwUnused0; // not used, was memory pointer Port0
DWORD dwUnused1; // not used, was memory pointer Port1
DWORD dwUnused2; // not used, was memory pointer Port2
DWORD pc;
DWORD d0;
DWORD d1;
DWORD rstkp;
DWORD rstk[8];
BYTE A[16];
BYTE B[16];
BYTE C[16];
BYTE D[16];
BYTE R0[16];
BYTE R1[16];
BYTE R2[16];
BYTE R3[16];
BYTE R4[16];
BYTE ST[4];
BYTE HST;
BYTE P;
WORD out;
WORD in;
BOOL SoftInt;
BOOL Shutdn;
BOOL mode_dec;
BOOL inte; // interrupt status flag (FALSE = int in service)
BOOL intk; // 1 ms keyboard scan flag (TRUE = enable)
BOOL intd; // keyboard interrupt pending (TRUE = int pending)
BOOL carry;
WORD crc;
WORD wPort2Crc; // fingerprint of port2
WORD wRomCrc; // fingerprint of ROM
#if defined _USRDLL // DLL version
QWORD cycles; // oscillator cycles
#else // EXE version
DWORD cycles; // oscillator cycles
DWORD cycles_reserved; // reserved for MSB of oscillator cycles
#endif
DWORD dwKdnCycles; // cpu cycles at start of 1ms key handler
UINT Bank_FF; // save state of HP48GX port2 or state of HP49G ROM FF
UINT FlashRomState; // WSM state of flash memory (unused)
BYTE cards_status;
BYTE IORam[64]; // I/O hardware register
UINT IOBase; // address of I/O modules page
BOOL IOCfig; // I/O module configuration flag
BYTE P0Base, BSBase, P1Base, P2Base; // address of modules first 2KB page
BYTE P0Size, BSSize, P1Size, P2Size; // mapped size of module in 2KB
BYTE P0End, BSEnd, P1End, P2End; // address of modules last 2KB page
BOOL P0Cfig, BSCfig, P1Cfig, P2Cfig; // module address configuration flag
BOOL P0Cfg2, BSCfg2, P1Cfg2, P2Cfg2; // module size configuration flag
BYTE t1;
DWORD t2;
BOOL bShutdnWake; // flag for wake up from SHUTDN mode
BYTE Keyboard_Row[9];
WORD IR15X;
UINT Keyboard_State; // not used
signed short loffset;
signed int width;
UINT boffset;
UINT lcounter;
UINT sync; // not used
BYTE contrast;
BOOL dispon; // not used
DWORD start1;
DWORD start12;
DWORD end1;
DWORD start2, end2;
// CdB for HP: add apples header
DWORD d0size; // no. of header display lines
BYTE d0memory[4096*2]; // memory for header display area
DWORD d0offset; // offset inside the header display for the content
DWORD d0address; // address in saturn addr area for d0memory (2 pages)
// BOOL d0Cfig; // modul configured
} Chipset_t;
// additional Saturnator registers and Apple hardware
typedef struct
{
BYTE byType[4]; // "SPL" Saturn PLus
QWORD fld[7]; // user defined field masks F1-F7
BOOL d0Cfig; // display memory modul configured
DWORD d0address; // address in saturn addr area for d0memory (2 pages)
DWORD d0size; // no. of header display lines
DWORD d0offset; // offset inside the display memory for the content
BYTE d0memory[4096*2]; // 4KB memory for header display area
} APPLE_CHIPSET;

79
app/src/main/cpp/UDP.C Normal file
View file

@ -0,0 +1,79 @@
/*
* udp.c
*
* This file is part of Emu48
*
* Copyright (C) 2011 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
TCHAR szUdpServer[1024] = _T("localhost");
WORD wUdpPort = 5025; // scpi-raw
static IN_ADDR ip_addr = { 255, 255, 255, 255 };
VOID ResetUdp(VOID)
{
ip_addr.s_addr = INADDR_NONE; // invalidate saved UDP address
return;
}
BOOL SendByteUdp(BYTE byData)
{
WSADATA wsd;
SOCKET sClient;
SOCKADDR_IN sServer;
BOOL bErr = TRUE;
VERIFY(WSAStartup(MAKEWORD(1,1),&wsd) == 0);
if (ip_addr.s_addr == INADDR_NONE) // IP address not specified
{
LPSTR lpszIpAddr;
#if defined _UNICODE
DWORD dwLength = lstrlen(szUdpServer) + 1;
if ((lpszIpAddr = (LPSTR) _alloca(dwLength)) == NULL)
return TRUE; // server not found
WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK,
szUdpServer, dwLength,
lpszIpAddr, dwLength, NULL, NULL);
#else
lpszIpAddr = szUdpServer;
#endif
ip_addr.s_addr = inet_addr(lpszIpAddr);
// not a valid ip address -> try to get ip address from name server
if (ip_addr.s_addr == INADDR_NONE)
{
PHOSTENT host = gethostbyname(lpszIpAddr);
if (host == NULL)
{
return TRUE; // server not found
}
ip_addr.s_addr = ((PIN_ADDR) host->h_addr_list[0])->s_addr;
}
}
// create UDP socket
if ((sClient = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET)
{
sServer.sin_family = AF_INET;
sServer.sin_port = htons(wUdpPort);
sServer.sin_addr.s_addr = ip_addr.s_addr;
// transmit data byte
bErr = sendto(sClient, (LPCCH) &byData, sizeof(byData), 0, (LPSOCKADDR) &sServer, sizeof(sServer)) == SOCKET_ERROR;
closesocket(sClient);
}
WSACleanup(); // cleanup network stack
return bErr;
}

View file

@ -0,0 +1,14 @@
//
// Created by cosnier on 12/11/2018.
//
#include <jni.h>
#include <stdio.h>
JNIEXPORT jstring JNICALL
Java_com_regis_cosnier_emu48_MainActivity_stringFromJNI(
JNIEnv *env,
jobject thisz) {
// std::string hello = "Hello from C++";
// return env->NewStringUTF(hello.c_str());
return (*env)->NewStringUTF(env, "Hello from JNI !");
}

View file

@ -0,0 +1,68 @@
package com.regis.cosnier.emu48;
import android.os.Bundle;
import android.widget.TextView;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
}

View file

@ -0,0 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeWidth="1"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View file

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#008577"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_main" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@android:drawable/ic_dialog_email" />
</android.support.design.widget.CoordinatorLayout>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".MainActivity"
tools:showIn="@layout/activity_main">
<TextView
android:id="@+id/sample_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

View file

@ -0,0 +1,10 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.regis.cosnier.emu48.MainActivity">
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="@string/action_settings"
app:showAsAction="never" />
</menu>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
</resources>

View file

@ -0,0 +1,3 @@
<resources>
<dimen name="fab_margin">16dp</dimen>
</resources>

View file

@ -0,0 +1,4 @@
<resources>
<string name="app_name">Emu48</string>
<string name="action_settings">Settings</string>
</resources>

View file

@ -0,0 +1,20 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
</resources>

View file

@ -0,0 +1,17 @@
package com.regis.cosnier.emu48;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

27
build.gradle Normal file
View file

@ -0,0 +1,27 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

15
gradle.properties Normal file
View file

@ -0,0 +1,15 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

172
gradlew vendored Normal file
View file

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
gradlew.bat vendored Normal file
View file

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

9
local.properties Normal file
View file

@ -0,0 +1,9 @@
## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Mon Nov 12 10:19:12 CET 2018
ndk.dir=C\:\\Users\\cosnier\\AppData\\Local\\Android\\Sdk\\ndk-bundle
sdk.dir=C\:\\Users\\cosnier\\AppData\\Local\\Android\\Sdk

1
settings.gradle Normal file
View file

@ -0,0 +1 @@
include ':app'