1
0
mirror of https://github.com/irmen/ksim65.git synced 2024-06-01 21:41:31 +00:00

Compare commits

...

70 Commits
v1.5 ... master

Author SHA1 Message Date
Irmen de Jong
3f28ef6cad update gradle 2023-10-30 20:24:14 +01:00
Irmen de Jong
0fda62370e updates 2023-08-30 13:59:16 +02:00
Irmen de Jong
6812ab4b09 updates 2023-08-15 13:30:01 +02:00
Irmen de Jong
67c70abb41 build fixes 2023-05-26 20:14:55 +02:00
Irmen de Jong
5cc3f8fddd kotlin 1.7.10 2022-08-13 21:24:12 +02:00
Irmen de Jong
87c7aad49a update gradle wrapper to 7.4 2022-03-12 23:22:46 +01:00
Irmen de Jong
1ca771840b kotlin 1.6.10 2022-01-09 03:53:50 +01:00
Irmen de Jong
b17b72b6b5 remote broken dokka build target, upgrade to kotlin 1.5.30 2021-09-19 18:27:25 +02:00
Irmen de Jong
61bb920776 ide files 2021-09-19 18:12:35 +02:00
Irmen de Jong
6c73852b5e update kotlin version 2021-07-06 23:37:19 +02:00
Irmen de Jong
6dc433417d updated to Kotlin 1.4.20 and JDK 11 2020-12-19 14:58:48 +01:00
Irmen de Jong
f8b3213b41 update travix 2020-10-23 00:07:26 +02:00
Irmen de Jong
b2b4b0ab83 gradle upgrade 2020-10-22 23:53:59 +02:00
Irmen de Jong
1cbb006577 updated to new kotlin version 2020-10-13 00:06:28 +02:00
Irmen de Jong
b8691db38e version 1.9 2020-07-07 18:50:02 +02:00
Irmen de Jong
d1d433c3a6 replaced fixed 8x16 bitmap font by psf font 2020-03-17 00:01:45 +01:00
Irmen de Jong
3925c80258 another link to illegal instructions 2020-03-16 21:59:38 +01:00
Irmen de Jong
c2d6954327 added default vice rom path to search list 2020-03-13 17:16:41 +01:00
Irmen de Jong
0670a85f88 upgrade kotlin sdk version, optimized hex number output 2020-03-07 01:17:48 +01:00
Irmen de Jong
7522d3cb3b added joystick to C64 emulation (via numpad keys) 2020-03-01 18:38:00 +01:00
Irmen de Jong
99942748f9 when 2020-02-27 03:57:32 +01:00
Irmen de Jong
323098f645 doc 2020-02-21 20:11:17 +01:00
Irmen de Jong
d9f1a76c47 doc 2020-02-21 02:21:55 +01:00
Irmen de Jong
95733df9af exclude c64 specific tests because of roms requirement 2020-02-21 02:15:10 +01:00
Irmen de Jong
ec9b80433f doc 2020-02-21 01:57:00 +01:00
Irmen de Jong
cd00191dcf ver 1.8 2020-02-21 01:46:34 +01:00
Irmen de Jong
31962d083f more fun c64 demos 2020-02-21 01:28:50 +01:00
Irmen de Jong
1e27e5bae4 corrected BRK flag incompatibility + unit tests 2020-02-21 01:12:38 +01:00
Irmen de Jong
5667c00d85 fixed cycle times, implemented various illegal opcodes. NesTest now runs flawlessly 2020-02-20 03:32:06 +01:00
Irmen de Jong
35cbe4e3ca tweak 6510 io port and fix overflow bug in TOD 2020-02-20 00:01:54 +01:00
Irmen de Jong
99d8f5cd97 fix 'a' command 2020-02-19 01:13:18 +01:00
Irmen de Jong
be8716c4a4 use assembler instead of raw bytes 2020-02-19 00:48:05 +01:00
Irmen de Jong
deaf79fcc2 introduced separate Assembler class 2020-02-19 00:29:07 +01:00
Irmen de Jong
c619ddabf1 introduced separate Disassembler class 2020-02-18 22:01:12 +01:00
Irmen de Jong
d5f533c300 fix power on values of cpu port registers 2020-02-18 19:51:05 +01:00
Irmen de Jong
62e2f1663a test tweak 2020-02-18 04:48:56 +01:00
Irmen de Jong
57e9bacef9 fix vic bank screen address miscalculation 2020-02-18 04:21:35 +01:00
Irmen de Jong
2ad73432f6 do not crash anymore when multicolor mode is enabled 2020-02-18 02:54:04 +01:00
Irmen de Jong
1123ddf482 trying to add the nestest rom 2020-02-18 02:08:07 +01:00
Irmen de Jong
08880c5d77 added the 'bbc beeb' bcd tests 2020-02-18 01:25:01 +01:00
Irmen de Jong
3888b142d2 split up the test suite some more 2020-02-17 23:45:20 +01:00
Irmen de Jong
a8874fd05a notes 2020-02-17 02:17:34 +01:00
Irmen de Jong
5d9c54eaf6 jcenter 2020-02-17 00:06:14 +01:00
Irmen de Jong
ffbd5050d6 jcenter 2020-02-16 23:54:52 +01:00
Irmen de Jong
0dd97ba41c todo sprite collisions 2020-02-16 23:04:51 +01:00
Irmen de Jong
f3f1abab88 updated c64 image 2020-02-16 23:02:56 +01:00
Irmen de Jong
cc1fb9716b fixed monitor disassemble and assemble commands 2020-02-16 22:45:54 +01:00
Irmen de Jong
6db5e792d6 optimized layout of debug/monitor window 2020-02-16 17:52:29 +01:00
Irmen de Jong
606a587bb5 monitor assembler address now supports '*' and relative addresses to that 2020-02-16 16:30:49 +01:00
Irmen de Jong
3f86d5185e cpu irq/nmi now via "pin assert" instead of pending statuses 2020-02-16 16:01:41 +01:00
Irmen de Jong
c327c59c8b cpu jump loop detection added 2020-02-16 15:40:51 +01:00
Irmen de Jong
30351b44ba version 2020-02-16 13:40:36 +01:00
Irmen de Jong
f61242a17b fix irq frequency in example machine (was way too fast and overlapped) 2020-02-16 13:39:46 +01:00
Irmen de Jong
d940b9d136 fix cpu irq/nmi handling 2020-02-16 06:01:11 +01:00
Irmen de Jong
30b164bb6d tweak cpu irq handling, updating Klaus Dormann's functional irq tests 2020-02-16 05:37:23 +01:00
Irmen de Jong
de60698349 updating Klaus Dormann's functional tests 2020-02-12 22:26:19 +01:00
Irmen de Jong
7f3dd9c95d fix disassembly of address wrap arounds 2020-02-09 16:36:57 +01:00
Irmen de Jong
b7ebf6c922 updating Klaus Dormann's functional tests 2020-02-09 16:12:31 +01:00
Irmen de Jong
7fb8feb676 try to gpg sign for bintray 2020-02-06 00:57:53 +01:00
Irmen de Jong
b3334a23b9 forgot to checkin the bus changes for memory mapping 2020-02-05 01:27:04 +01:00
Irmen de Jong
8b84a7c653 fix unit test 2020-02-05 01:24:45 +01:00
Irmen de Jong
43b2bec5da no longer attach roms to bus old-style 2020-02-05 01:22:32 +01:00
Irmen de Jong
81ae12b809 memory components reading and writing now done via offset instead of address 2020-02-05 01:02:27 +01:00
Irmen de Jong
b4a6709646 rom byte loading tweak 2020-02-04 23:56:58 +01:00
Irmen de Jong
92e0c13c70 version 1.6 2020-02-04 00:03:24 +01:00
Irmen de Jong
5deeb50c49 implemented banking in/out the char rom 2020-02-03 23:53:18 +01:00
Irmen de Jong
9cba058fd7 implemented custom character sets (read from RAM) 2020-02-03 23:18:40 +01:00
Irmen de Jong
5ef6965c82 clean up 2020-02-02 19:33:57 +01:00
Irmen de Jong
050c1d4478 updated gradlewrapper 2020-02-02 13:41:24 +01:00
Irmen de Jong
8850638f11 version 2020-02-01 18:54:49 +01:00
341 changed files with 112616 additions and 3383 deletions

View File

@ -12,6 +12,9 @@
<MarkdownNavigatorCodeStyleSettings>
<option name="RIGHT_MARGIN" value="80" />
</MarkdownNavigatorCodeStyleSettings>
<codeStyleSettings language="Markdown">
<option name="RIGHT_MARGIN" value="80" />
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<option name="KEEP_LINE_BREAKS" value="false" />

6
.idea/compiler.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" />
</component>
</project>

View File

@ -15,8 +15,6 @@
<option value="$PROJECT_DIR$" />
</set>
</option>
<option name="useAutoImport" value="true" />
<option name="useQualifiedModuleNames" value="true" />
</GradleProjectSettings>
</option>
</component>

View File

@ -26,5 +26,10 @@
<option name="name" value="maven" />
<option name="url" value="https://jitpack.io" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenRepo" />
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
</component>
</project>

6
.idea/kotlinc.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.10" />
</component>
</project>

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4" />

View File

@ -12,7 +12,7 @@
<component name="MarkdownProjectSettings">
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" synchronizePreviewPosition="true" highlightPreviewType="LINE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="true" showSelectionInPreview="true" lastLayoutSetsDefault="false">
<PanelProvider>
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.panel" providerName="Default - Swing" />
<provider providerId="com.vladsch.md.nav.editor.javafx.html.panel" providerName="JavaFX WebView" />
</PanelProvider>
</PreviewSettings>
<ParserSettings gitHubSyntaxChange="false" correctedInvalidSettings="false" emojiShortcuts="1" emojiImages="0">
@ -36,7 +36,7 @@
</ParserSettings>
<HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" addPageHeader="false" imageUriSerials="false" addDocTypeHtml="true" noParaTags="false" plantUmlConversion="0">
<GeneratorProvider>
<provider providerId="com.vladsch.idea.multimarkdown.editor.text.html.generator" providerName="Unmodified HTML Generator" />
<provider providerId="com.vladsch.md.nav.editor.javafx.html.generator" providerName="JavaFx HTML Generator" />
</GeneratorProvider>
<headerTop />
<headerBottom />
@ -45,9 +45,11 @@
</HtmlSettings>
<CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssUriSerial="true" isCssTextEnabled="false" isDynamicPageWidth="true">
<StylesheetProvider>
<provider providerId="com.vladsch.idea.multimarkdown.editor.text.html.css" providerName="No Stylesheet" />
<provider providerId="com.vladsch.md.nav.editor.javafx.html.css" providerName="Default JavaFx Stylesheet" />
</StylesheetProvider>
<ScriptProviders />
<ScriptProviders>
<provider providerId="com.vladsch.md.nav.editor.hljs.html.script" providerName="HighlightJS Script" />
</ScriptProviders>
<cssText />
<cssUriHistory />
</CssSettings>

View File

@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="openjdk-11" project-jdk-type="JavaSDK" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="openjdk-11" project-jdk-type="JavaSDK" />
</project>

View File

@ -1,10 +0,0 @@
language: java
sudo: false
# jdk: openjdk8
# dist: xenial
before_install:
- chmod +x gradlew
script:
- gradle test

View File

@ -1,34 +1,49 @@
[![saythanks](https://img.shields.io/badge/say-thanks-ff69b4.svg)](https://saythanks.io/to/irmen)
[![Build Status](https://travis-ci.org/irmen/ksim65.svg?branch=master)](https://travis-ci.org/irmen/ksim65)
# KSim65 - Kotlin/JVM 6502/65C02 microprocessor simulator
*Written by Irmen de Jong (irmen@razorvine.net)*
*Software license: MIT, see file LICENSE*
![6502](https://upload.wikimedia.org/wikipedia/commons/thumb/4/43/KL_MOS_6502.jpg/320px-KL_MOS_6502.jpg)
This is a Kotlin/JVM library that simulates the 8-bit 6502 and 65C02 microprocessors,
which became very popular in the the early 1980's.
which became very popular in the the early 1980's.
Properties of this simulator:
- Written in Kotlin. It is low-level code, but hopefully still readable :-)
- Designed to simulate various hardware components (bus, cpu, memory, i/o controllers)
- IRQ and NMI simulation
- Aims to simulate correct instruction cycle timing, but is not 100% cycle exact for simplicity
- Aims to implements all 6502 and 65c02 instructions, including the 'illegal' 6502 instructions (not yet done)
- correct BCD mode for adc/sbc instructions on both cpu types
- written in Kotlin. It is low-level code, but hopefully still readable :-)
- simulates various hardware components (bus, cpu, memory, i/o controllers)
- IRQ and NMI
- instruction cycle times are simulated (however the *internal* cpu behavior is not cycle-exact for simplicity reasons)
- has all 6502 and 65c02 instructions, including many of the 'illegal' 6502 instructions (goal is 100% eventually)
- correct BCD mode for adc/sbc instructions on both cpu types
- passes several extensive unit test suites that verify instruction and cpu flags behavior
- provide a few virtual example machines, one of which is a Commodore-64
- simple debugging machine monitor, which basic disassembler and assembler functions
- provide a few virtual example machines, one of which is a fairly capable Commodore-64
## Documentation
Still to be written. For now, use the source ;-)
## Using it as a library in your own project
**TODO move to another repository for published packages.**
You can simply add it as a dependency to your project.
For Maven:
<dependency>
<groupId>net.razorvine</groupId>
<artifactId>ksim65</artifactId>
<version>1.10</version>
<type>pom</type>
</dependency>
For Gradle:
implementation 'net.razorvine:ksim65:1.10'
Update the version as required.
## Virtual machine examples
@ -45,3 +60,36 @@ various timers and IRQs. It's not cycle perfect, and the video display is drawn
so raster splits/rasterbars are impossible. But many other things work fine.
![C64 emulation](c64.png)
### License information
Ksim65 itself is licensed under the MIT software license, see file LICENSE.
It includes the 'Spleen' bitmap font (https://github.com/fcambus/spleen),
which has the following license (BSD):
Copyright (c) 2018-2020, Frederic Cambus
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,4 +1,3 @@
import org.jetbrains.dokka.gradle.DokkaTask
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.util.*
import kotlin.math.max
@ -6,32 +5,39 @@ import kotlin.math.max
plugins {
// Apply the Kotlin JVM plugin to add support for Kotlin on the JVM.
kotlin("jvm") version "1.3.61"
kotlin("jvm") version "1.9.10"
`maven-publish`
application
id("org.jetbrains.dokka") version "0.10.0"
id("com.jfrog.bintray") version "1.8.4"
java
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
allprojects {
val versionProps = Properties().also {
it.load(File("$projectDir/src/main/resources/version.properties").inputStream())
}
version = versionProps["version"] as String
group = "net.razorvine"
base.archivesBaseName = "ksim65"
// base.archivesBaseName = "ksim65"
repositories {
// Use jcenter for resolving dependencies.
// You can declare any Maven/Ivy/file repository here.
mavenLocal()
jcenter()
mavenCentral()
maven("https://jitpack.io")
}
}
dependencies {
// Align versions of all Kotlin components
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
implementation("org.jetbrains.kotlin:kotlin-reflect")
// Use the Kotlin JDK 8 standard library.
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
@ -40,11 +46,11 @@ dependencies {
// Use the Kotlin JUnit5 integration.
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.4.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.4.0")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
subprojects.forEach {
archives(it)
implementation(it)
}
}
@ -61,35 +67,27 @@ tasks {
}
withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
named<DokkaTask>("dokka") {
outputFormat = "html"
outputDirectory = "$buildDir/kdoc"
configuration {
skipEmptyPackages = true
}
kotlinOptions.jvmTarget = "11"
}
}
val c64emuScript by tasks.registering(CreateStartScripts::class) {
outputDir = File(project.buildDir, "bin")
outputDir = project.layout.buildDirectory.dir("bin").get().asFile
applicationName = "c64emu"
mainClassName = "razorvine.c64emu.C64MainKt"
mainClass.set("razorvine.c64emu.C64MainKt")
classpath = project.tasks["jar"].outputs.files+project.configurations.runtimeClasspath.get()
}
val ehbasicScript by tasks.registering(CreateStartScripts::class) {
outputDir = File(project.buildDir, "bin")
outputDir = project.layout.buildDirectory.dir("bin").get().asFile
applicationName = "ehbasic"
mainClassName = "razorvine.examplemachines.EhBasicMainKt"
mainClass.set("razorvine.examplemachines.EhBasicMainKt")
classpath = project.tasks["jar"].outputs.files+project.configurations.runtimeClasspath.get()
}
application {
applicationName = "ksim65vm"
mainClassName = "razorvine.examplemachines.MachineMainKt"
mainClass.set("razorvine.examplemachines.MachineMainKt")
applicationDistribution.into("bin") {
from(c64emuScript, ehbasicScript)
fileMode = 493
@ -102,12 +100,6 @@ val sourcesJar by tasks.registering(Jar::class) {
from(sourceSets.main.get().allSource)
}
val dokkaDocs by tasks.registering(Jar::class) {
dependsOn("dokka")
archiveClassifier.set("kdoc")
from(fileTree(File(project.buildDir, "kdoc")))
}
publishing {
repositories {
mavenLocal()
@ -116,23 +108,6 @@ publishing {
register("mavenJava", MavenPublication::class) {
from(components["java"])
artifact(sourcesJar.get())
artifact(dokkaDocs.get())
}
}
}
bintray {
user = System.getenv("BINTRAY_USER")
key = System.getenv("BINTRAY_KEY")
setPublications(* publishing.publications.names.toTypedArray())
// setConfigurations("archives")
pkg = PackageConfig().also {
it.name = "ksim65"
it.repo = "maven"
it.setLicenses("MIT")
it.vcsUrl = "https://github.com/irmen/ksim65.git"
it.setLabels("6502", "retro", "emulation", "c64")
it.githubRepo = it.vcsUrl
}
}

BIN
c64.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

After

Width:  |  Height:  |  Size: 237 KiB

BIN
c64testprgs/atlantis.prg Normal file

Binary file not shown.

BIN
c64testprgs/inaloop.prg Normal file

Binary file not shown.

BIN
c64testprgs/joytest.prg Normal file

Binary file not shown.

BIN
free-c64-roms/basic Normal file

Binary file not shown.

BIN
free-c64-roms/chargen Normal file

Binary file not shown.

BIN
free-c64-roms/kernal Normal file

Binary file not shown.

24
free-c64-roms/readme.txt Normal file
View File

@ -0,0 +1,24 @@
Free/open source roms for the C64
See https://github.com/MEGA65/open-roms
The following copyright notices apply to the entirety of this package,
including each source file, unless otherwise noted in each file or directory.
Copyright Paul Gardner-Stephen, 2019.
Copyright Roman Standzikowski (FeralChil64), 2019-2020.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.

View File

@ -1,5 +1,5 @@
kotlin.code.style=official
org.gradle.caching=true
org.gradle.console=rich
org.gradle.parallel=true
org.gradle.daemon=true
kotlin.code.style=official

Binary file not shown.

View File

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

269
gradlew vendored
View File

@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -17,78 +17,113 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# 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
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
APP_BASE_NAME=${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='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# 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
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | 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"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
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
@ -105,79 +140,95 @@ 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 or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; 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=`expr $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" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
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, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# 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"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

25
gradlew.bat vendored
View File

@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@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="-Xmx64m" "-Xms64m"
@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -51,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -61,28 +64,14 @@ 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%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell

View File

@ -0,0 +1,48 @@
package razorvine.c64emu
import razorvine.ksim65.components.Address
import razorvine.ksim65.components.Rom
import razorvine.ksim65.components.UByte
/**
* The C64's bus is a bit peculiar:
* appearance of RAM or ROM in certain address ranges can be dynamically controlled
* via the 6510's IO port register in $00/$01, "bank switching".
* More info here https://www.c64-wiki.com/wiki/Bank_Switching
*
* Note: we don't implement the expansion port's _EXROM and _GAME lines that are used
* for mapping in cartridge ROMs into the address space.
*/
class Bus6510(private val ioPort: CpuIoPort,
private val chargen: Rom,
private val basic: Rom,
private val kernal: Rom): razorvine.ksim65.Bus() {
override fun read(address: Address): UByte {
return when(address) {
in 0x0000..0x9fff -> super.read(address) // always RAM
in 0xa000..0xbfff -> {
// BASIC or RAM
if(ioPort.loram && ioPort.hiram)
basic[address - 0xa000]
else
super.read(address)
}
in 0xc000..0xcfff -> super.read(address) // always RAM
in 0xd000..0xdfff -> {
// IO or CHAR ROM
if(ioPort.charen)
super.read(address)
else
chargen[address - 0xd000]
}
else -> {
// 0xe000..0xffff, KERNAL or RAM
if(ioPort.hiram)
kernal[address - 0xe000]
else
super.read(address)
}
}
}
}

View File

@ -9,12 +9,20 @@ import java.awt.event.KeyEvent
/**
* Minimal simulation of the MOS 6526 CIA chip.
* Depending on what CIA it is (1 or 2), some registers do different things on the C64.
* This implementation provides a working keyboard matrix, TOD clock, and the essentials of the timer A and B.
* This implementation provides a working keyboard matrix, joystick in port#2 (cia 1),
* time of day clock, and the essentials of the timer A and B.
*/
class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemMappedComponent(startAddress, endAddress) {
private var ramBuffer = Array<UByte>(endAddress-startAddress+1) { 0 }
private var regPRA = 0xff
// joystick in port 2 configuration (only works on cia#1)
private var joy2up = false
private var joy2down = false
private var joy2left = false
private var joy2right = false
private var joy2fire = false
class TimeOfDay {
private var updatedAt = 0L
private var startedAt = 0L
@ -52,6 +60,8 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
if (updatedAt != latchedTime) {
updatedAt = latchedTime
var elapsedSeconds = (latchedTime.toDouble()-startedAt)/1000.0+userStartTime
if(elapsedSeconds>60*3600)
elapsedSeconds=0.0 // TOD counds max 60 hours
hours = (elapsedSeconds/3600).toInt()
elapsedSeconds -= hours*3600
minutes = (elapsedSeconds/60).toInt()
@ -84,7 +94,7 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
totalCycles++
if (totalCycles%20000 == 0) {
// TOD resolution is 0.1 second, no need to update it in every cycle
// TOD resolution is 0.1 second, no need to update it in every bus cycle
tod.update()
}
@ -92,8 +102,8 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
// timer A is enabled, assume system cycles counting for now
timerAactual--
if (timerAactual == 0 && timerAinterruptEnabled) {
if (number == 1) cpu.irq()
else if (number == 2) cpu.nmi()
if (number == 1) cpu.irqAsserted = true
else if (number == 2) cpu.nmiAsserted = true
}
if (timerAactual < 0) timerAactual = if (ramBuffer[0x0e].toInt() and 0b00001000 != 0) 0 else timerAset
}
@ -108,8 +118,8 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
timerBactual--
}
if (timerBactual == 0 && timerBinterruptEnabled) {
if (number == 1) cpu.irq()
else if (number == 2) cpu.nmi()
if (number == 1) cpu.irqAsserted = true
else if (number == 2) cpu.nmiAsserted = true
}
if (timerBactual < 0) timerBactual = if (regCRB and 0b00001000 != 0) 0 else timerBset
}
@ -123,9 +133,14 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
timerAset = 0
timerBactual = 0
timerBset = 0
joy2up = false
joy2down = false
joy2left = false
joy2right = false
joy2fire = false
}
override fun get(address: Address): UByte {
override operator fun get(offset: Int): UByte {
fun scanColumn(vararg keys: HostKeyPress): UByte {
var bits = 0b10000000
var presses = 0
@ -136,72 +151,86 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
return (presses.inv() and 255).toShort()
}
val register = (address-startAddress) and 15
if (number == 1 && register == 0x01) {
// register 1 on CIA#1 is the keyboard data port
// if bit is cleared in PRA, contains keys pressed in that column of the matrix
return when (regPRA) {
0b00000000 -> {
// check if any keys are pressed at all (by checking all columns at once)
if (hostKeyPresses.isEmpty()) 0xff.toShort() else 0x00.toShort()
}
0b11111110 -> {
// read column 0
scanColumn(HostKeyPress(KeyEvent.VK_DOWN), HostKeyPress(KeyEvent.VK_F5), HostKeyPress(KeyEvent.VK_F3),
HostKeyPress(KeyEvent.VK_F1), HostKeyPress(KeyEvent.VK_F7), HostKeyPress(KeyEvent.VK_RIGHT),
HostKeyPress(KeyEvent.VK_ENTER), HostKeyPress(KeyEvent.VK_BACK_SPACE))
}
0b11111101 -> {
// read column 1
scanColumn(HostKeyPress(KeyEvent.VK_SHIFT), // left shift
HostKeyPress(KeyEvent.VK_E), HostKeyPress(KeyEvent.VK_S), HostKeyPress(KeyEvent.VK_Z),
HostKeyPress(KeyEvent.VK_4), HostKeyPress(KeyEvent.VK_A), HostKeyPress(KeyEvent.VK_W),
HostKeyPress(KeyEvent.VK_3))
}
0b11111011 -> {
// read column 2
scanColumn(HostKeyPress(KeyEvent.VK_X), HostKeyPress(KeyEvent.VK_T), HostKeyPress(KeyEvent.VK_F),
HostKeyPress(KeyEvent.VK_C), HostKeyPress(KeyEvent.VK_6), HostKeyPress(KeyEvent.VK_D),
HostKeyPress(KeyEvent.VK_R), HostKeyPress(KeyEvent.VK_5))
}
0b11110111 -> {
// read column 3
scanColumn(HostKeyPress(KeyEvent.VK_V), HostKeyPress(KeyEvent.VK_U), HostKeyPress(KeyEvent.VK_H),
HostKeyPress(KeyEvent.VK_B), HostKeyPress(KeyEvent.VK_8), HostKeyPress(KeyEvent.VK_G),
HostKeyPress(KeyEvent.VK_Y), HostKeyPress(KeyEvent.VK_7))
}
0b11101111 -> {
// read column 4
scanColumn(HostKeyPress(KeyEvent.VK_N), HostKeyPress(KeyEvent.VK_O), HostKeyPress(KeyEvent.VK_K),
HostKeyPress(KeyEvent.VK_M), HostKeyPress(KeyEvent.VK_0), HostKeyPress(KeyEvent.VK_J),
HostKeyPress(KeyEvent.VK_I), HostKeyPress(KeyEvent.VK_9))
}
0b11011111 -> {
// read column 5
scanColumn(HostKeyPress(KeyEvent.VK_COMMA), HostKeyPress(KeyEvent.VK_AT), HostKeyPress(KeyEvent.VK_COLON),
HostKeyPress(KeyEvent.VK_PERIOD), HostKeyPress(KeyEvent.VK_MINUS), HostKeyPress(KeyEvent.VK_L),
HostKeyPress(KeyEvent.VK_P), HostKeyPress(KeyEvent.VK_PLUS))
}
0b10111111 -> {
// read column 6
scanColumn(HostKeyPress(KeyEvent.VK_SLASH), HostKeyPress(KeyEvent.VK_CIRCUMFLEX), HostKeyPress(KeyEvent.VK_EQUALS),
HostKeyPress(KeyEvent.VK_SHIFT, rightSide = true), // right shift
HostKeyPress(KeyEvent.VK_HOME), HostKeyPress(KeyEvent.VK_SEMICOLON), HostKeyPress(KeyEvent.VK_ASTERISK),
HostKeyPress(KeyEvent.VK_DEAD_TILDE) // pound sign
)
}
0b01111111 -> {
// read column 7
scanColumn(HostKeyPress(KeyEvent.VK_ESCAPE), HostKeyPress(KeyEvent.VK_Q), HostKeyPress(KeyEvent.VK_ALT),
HostKeyPress(KeyEvent.VK_SPACE), HostKeyPress(KeyEvent.VK_2), HostKeyPress(KeyEvent.VK_CONTROL),
HostKeyPress(KeyEvent.VK_BACK_QUOTE), HostKeyPress(KeyEvent.VK_1))
}
else -> {
// invalid column selection
0xff
val register = offset and 15
if(number==1) {
// first CIA has keyboard matrix
if(register==0x00) {
// reading $dc00 is joystick in port #2
return (0b01100000
or (if(joy2up) 0 else 0b00000001)
or (if(joy2down) 0 else 0b00000010)
or (if(joy2left) 0 else 0b00000100)
or (if(joy2right) 0 else 0b00001000)
or (if(joy2fire) 0 else 0b00010000)).toShort()
} else if(register==0x01) {
// register 1 on CIA#1 is the keyboard data port (and joystick #1...)
// if bit is cleared in PRA, contains keys pressed in that column of the matrix
// NOTE: we do not emulate a joystick in port #1 as this conflicts with the keyboard.
// just use the joystick in port #2 for now...
return when (regPRA) {
0b00000000 -> {
// check if any keys are pressed at all (by checking all columns at once)
if (hostKeyPresses.isEmpty()) 0xff.toShort() else 0x00.toShort()
}
0b11111110 -> {
// read column 0
scanColumn(HostKeyPress(KeyEvent.VK_DOWN), HostKeyPress(KeyEvent.VK_F5), HostKeyPress(KeyEvent.VK_F3),
HostKeyPress(KeyEvent.VK_F1), HostKeyPress(KeyEvent.VK_F7), HostKeyPress(KeyEvent.VK_RIGHT),
HostKeyPress(KeyEvent.VK_ENTER), HostKeyPress(KeyEvent.VK_BACK_SPACE))
}
0b11111101 -> {
// read column 1
scanColumn(HostKeyPress(KeyEvent.VK_SHIFT), // left shift
HostKeyPress(KeyEvent.VK_E), HostKeyPress(KeyEvent.VK_S), HostKeyPress(KeyEvent.VK_Z),
HostKeyPress(KeyEvent.VK_4), HostKeyPress(KeyEvent.VK_A), HostKeyPress(KeyEvent.VK_W),
HostKeyPress(KeyEvent.VK_3))
}
0b11111011 -> {
// read column 2
scanColumn(HostKeyPress(KeyEvent.VK_X), HostKeyPress(KeyEvent.VK_T), HostKeyPress(KeyEvent.VK_F),
HostKeyPress(KeyEvent.VK_C), HostKeyPress(KeyEvent.VK_6), HostKeyPress(KeyEvent.VK_D),
HostKeyPress(KeyEvent.VK_R), HostKeyPress(KeyEvent.VK_5))
}
0b11110111 -> {
// read column 3
scanColumn(HostKeyPress(KeyEvent.VK_V), HostKeyPress(KeyEvent.VK_U), HostKeyPress(KeyEvent.VK_H),
HostKeyPress(KeyEvent.VK_B), HostKeyPress(KeyEvent.VK_8), HostKeyPress(KeyEvent.VK_G),
HostKeyPress(KeyEvent.VK_Y), HostKeyPress(KeyEvent.VK_7))
}
0b11101111 -> {
// read column 4
scanColumn(HostKeyPress(KeyEvent.VK_N), HostKeyPress(KeyEvent.VK_O), HostKeyPress(KeyEvent.VK_K),
HostKeyPress(KeyEvent.VK_M), HostKeyPress(KeyEvent.VK_0), HostKeyPress(KeyEvent.VK_J),
HostKeyPress(KeyEvent.VK_I), HostKeyPress(KeyEvent.VK_9))
}
0b11011111 -> {
// read column 5
scanColumn(HostKeyPress(KeyEvent.VK_COMMA), HostKeyPress(KeyEvent.VK_AT), HostKeyPress(KeyEvent.VK_COLON),
HostKeyPress(KeyEvent.VK_PERIOD), HostKeyPress(KeyEvent.VK_MINUS), HostKeyPress(KeyEvent.VK_L),
HostKeyPress(KeyEvent.VK_P), HostKeyPress(KeyEvent.VK_PLUS))
}
0b10111111 -> {
// read column 6
scanColumn(HostKeyPress(KeyEvent.VK_SLASH), HostKeyPress(KeyEvent.VK_CIRCUMFLEX), HostKeyPress(KeyEvent.VK_EQUALS),
HostKeyPress(KeyEvent.VK_SHIFT, rightSide = true), // right shift
HostKeyPress(KeyEvent.VK_HOME), HostKeyPress(KeyEvent.VK_SEMICOLON), HostKeyPress(KeyEvent.VK_ASTERISK),
HostKeyPress(KeyEvent.VK_DEAD_TILDE) // pound sign
)
}
0b01111111 -> {
// read column 7
scanColumn(HostKeyPress(KeyEvent.VK_ESCAPE), HostKeyPress(KeyEvent.VK_Q), HostKeyPress(KeyEvent.VK_ALT),
HostKeyPress(KeyEvent.VK_SPACE), HostKeyPress(KeyEvent.VK_2), HostKeyPress(KeyEvent.VK_CONTROL),
HostKeyPress(KeyEvent.VK_BACK_QUOTE), HostKeyPress(KeyEvent.VK_1))
}
else -> {
// invalid column selection
0xff
}
}
}
} else ramBuffer[register]
}
return when (register) {
0x04 -> (timerAactual and 0xff).toShort()
@ -222,21 +251,8 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
}
}
private fun toBCD(data: Int): UByte {
val tens = data/10
val ones = data-tens*10
return ((tens shl 4) or ones).toShort()
}
private fun fromBCD(bcd: UByte): Int {
val ibcd = bcd.toInt()
val tens = ibcd ushr 4
val ones = ibcd and 0x0f
return tens*10+ones
}
override fun set(address: Address, data: UByte) {
val register = (address-startAddress) and 15
override operator fun set(offset: Int, data: UByte) {
val register = offset and 15
if (number == 1 && register == 0x00) {
// PRA data port A (select keyboard matrix column)
regPRA = data.toInt()
@ -294,6 +310,19 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
}
}
private fun toBCD(data: Int): UByte {
val tens = data/10
val ones = data-tens*10
return ((tens shl 4) or ones).toShort()
}
private fun fromBCD(bcd: UByte): Int {
val ibcd = bcd.toInt()
val tens = ibcd ushr 4
val ones = ibcd and 0x0f
return tens*10+ones
}
fun hostKeyPressed(event: KeyEvent) {
val rightSide = event.keyLocation == KeyEvent.KEY_LOCATION_RIGHT
val numpad = event.keyLocation == KeyEvent.KEY_LOCATION_NUMPAD
@ -372,4 +401,15 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu:
}
}
}
fun setJoystick2(up: Boolean, down: Boolean, left: Boolean, right: Boolean, fire: Boolean) {
if(number!=1)
throw NotImplementedError("joystick port 2 is connected to cia#1")
joy2up = up
joy2down = down
joy2left = left
joy2right = right
joy2fire = fire
}
}

View File

@ -1,45 +1,56 @@
package razorvine.c64emu
import razorvine.ksim65.Cpu6502
import razorvine.ksim65.components.Address
import razorvine.ksim65.components.MemMappedComponent
import razorvine.ksim65.components.UByte
/**
* The 6510's IO port located at $00/$01
* Controlling the memory layout, and cassette port (not processed at all).
* TODO: actually mapping the roms in and out of the address space. This requires some MMU type logic in the Bus class.
* TODO: there are a few functional tests that still fail. Is this not implemented correctly yet?
*/
class CpuIoPort(val cpu: Cpu6502) : MemMappedComponent(0x0000, 0x0001) {
class CpuIoPort : MemMappedComponent(0x0000, 0x0001) {
private var dataDirections: Int = 0
private var ioPort: Int = 0
private var loram: Boolean = false // Bit 0: LORAM signal. Selects ROM or RAM at 40960 ($A000). 1=BASIC, 0=RAM
private var hiram: Boolean = false // Bit 1: HIRAM signal. Selects ROM or RAM at 57344 ($E000). 1=Kernal, 0=RAM
private var charen: Boolean = false // Bit 2: CHAREN signal. Selects character ROM or I/O devices. 1=I/O, 0=ROM
var loram: Boolean = false // Bit 0: LORAM signal. Selects ROM or RAM at 40960 ($A000). 1=BASIC, 0=RAM
private set
var hiram: Boolean = false // Bit 1: HIRAM signal. Selects ROM or RAM at 57344 ($E000). 1=Kernal, 0=RAM
private set
var charen: Boolean = false // Bit 2: CHAREN signal. Selects character ROM or I/O devices. 1=I/O, 0=ROM
private set
override fun clock() { }
override fun reset() { }
override fun reset() {
dataDirections = 0xef
ioPort = 0x37
determineRoms()
}
override fun get(address: Address): UByte {
return if(address==0) dataDirections.toShort() else {
(ioPort or dataDirections.inv() and 0b00111111).toShort()
override operator fun get(offset: Int): UByte {
return if(offset==0) {
dataDirections.toShort()
} else {
if(dataDirections and 0b00100000 == 0)
(ioPort and 0b11011111).toShort() // bit 5 is low when input
else
ioPort.toShort()
}
}
override fun set(address: Address, data: UByte) {
if(address==0) {
override operator fun set(offset: Int, data: UByte) {
if(offset==0) {
dataDirections = data.toInt()
determineRoms()
} else {
ioPort = data.toInt()
ioPort = (ioPort and dataDirections.inv()) or (data.toInt() and dataDirections)
determineRoms()
}
}
private fun determineRoms() {
if (dataDirections and 0b00000001 != 0) loram = ioPort and 0b00000001 != 0
if (dataDirections and 0b00000010 != 0) hiram = ioPort and 0b00000010 != 0
if (dataDirections and 0b00000100 != 0) charen = ioPort and 0b00000100 != 0
loram = ioPort and 0b00000001 != 0
hiram = ioPort and 0b00000010 != 0
charen = ioPort and 0b00000100 != 0
}
}

View File

@ -2,6 +2,7 @@ package razorvine.c64emu
import razorvine.ksim65.Cpu6502
import razorvine.ksim65.components.MemoryComponent
import razorvine.ksim65.components.Rom
import razorvine.ksim65.components.UByte
import java.awt.Color
import java.awt.KeyboardFocusManager
@ -52,14 +53,14 @@ object ScreenDefs {
val colorPalette = Palette()
}
class MainC64Window(title: String, chargenData: ByteArray, val ram: MemoryComponent, val cpu: Cpu6502, val keypressCia: Cia) :
class MainC64Window(title: String, chargen: Rom, val ram: MemoryComponent, val cpu: Cpu6502, private val keypressCia: Cia) :
JFrame(title), KeyListener {
init {
defaultCloseOperation = EXIT_ON_CLOSE
isResizable = false
isFocusable = true
add(Screen(chargenData, ram))
add(Screen(chargen, ram))
addKeyListener(this)
pack()
setLocationRelativeTo(null)
@ -81,16 +82,50 @@ class MainC64Window(title: String, chargenData: ByteArray, val ram: MemoryCompon
// keyboard events:
override fun keyTyped(event: KeyEvent) {}
private var joy2up = false
private var joy2down = false
private var joy2left = false
private var joy2right = false
private var joy2fire = false
override fun keyPressed(event: KeyEvent) {
// '\' is mapped as RESTORE, this causes a NMI on the cpu
if (event.keyChar == '\\') {
cpu.nmi()
cpu.nmiAsserted = true
} else {
if(event.keyLocation==KeyEvent.KEY_LOCATION_NUMPAD) {
// numpad is joystick #2
if (event.keyChar in "789") joy2up = true
if (event.keyChar in "123") joy2down = true
if (event.keyChar in "741") joy2left = true
if (event.keyChar in "963") joy2right = true
if (event.keyChar in "05\n") joy2fire = true
keypressCia.setJoystick2(joy2up, joy2down, joy2left, joy2right, joy2fire)
} else {
keypressCia.hostKeyPressed(event)
}
}
}
override fun keyReleased(event: KeyEvent) {
if(event.keyLocation==KeyEvent.KEY_LOCATION_NUMPAD) {
// numpad is joystick #2
if (event.keyChar in "789") joy2up = false
if (event.keyChar in "123") joy2down = false
if (event.keyChar in "741") joy2left = false
if (event.keyChar in "963") joy2right = false
if (event.keyChar in "05\n") joy2fire = false
keypressCia.setJoystick2(joy2up, joy2down, joy2left, joy2right, joy2fire)
} else {
keypressCia.hostKeyPressed(event)
}
}
override fun keyReleased(event: KeyEvent) {
keypressCia.hostKeyPressed(event)
fun reset() {
joy2up = false
joy2down = false
joy2left = false
joy2right = false
joy2fire = false
}
}

View File

@ -2,6 +2,7 @@ package razorvine.c64emu
import razorvine.ksim65.components.Address
import razorvine.ksim65.components.MemoryComponent
import razorvine.ksim65.components.Rom
import razorvine.ksim65.components.UByte
import java.awt.*
import java.awt.image.BufferedImage
@ -12,9 +13,10 @@ import javax.swing.JPanel
* The rendering logic of the screen of the C64.
* It supports: Character mode,
* High res bitmap mode (320*200), Multicolor bitmap mode (160*200).
* TODO: Custom charsets from RAM. Multicolor character mode. Extended background color mode.
* TODO: Multicolor character mode. Extended background color mode.
* TODO: Horizontal smooth scrolling (+38 col mode). Vertical smooth scrolling (+24 row mode).
*/
internal class Screen(private val chargenData: ByteArray, val ram: MemoryComponent) : JPanel() {
internal class Screen(private val chargen: Rom, val ram: MemoryComponent) : JPanel() {
private val fullscreenImage: BufferedImage
private val fullscreenG2d: Graphics2D
@ -43,7 +45,7 @@ internal class Screen(private val chargenData: ByteArray, val ram: MemoryCompone
val offset = if (shifted) 256*8 else 0
for (char in 0..255) {
for (line in 0..7) {
val charbyte = chargenData[offset+char*8+line].toInt()
val charbyte = chargen[offset+char*8+line].toInt()
for (x in 0..7) {
if (charbyte and (0b10000000 ushr x) != 0) chars[char].setRGB(x, line, 0xffffff)
}
@ -108,7 +110,7 @@ internal class Screen(private val chargenData: ByteArray, val ram: MemoryCompone
}
private fun renderSprites(vicBank: Address) {
// TODO sprite-background priorities
// TODO sprite-background priorities, collisions
// TODO multicolor sprites
val spriteImage = fullscreenG2d.deviceConfiguration.createCompatibleImage(24, 21, Transparency.TRANSLUCENT)
val spriteGfx = spriteImage.graphics
@ -140,30 +142,23 @@ internal class Screen(private val chargenData: ByteArray, val ram: MemoryCompone
val color = ScreenDefs.colorPalette[ram[0xd027+sprite]].rgb
for (i in spritePixels.indices step 8) {
val bits = sprdata[i/8].toInt()
if (bits and 0b10000000 != 0) spritePixels[i] = color
if (bits and 0b01000000 != 0) spritePixels[i+1] = color
if (bits and 0b00100000 != 0) spritePixels[i+2] = color
if (bits and 0b00010000 != 0) spritePixels[i+3] = color
if (bits and 0b00001000 != 0) spritePixels[i+4] = color
if (bits and 0b00000100 != 0) spritePixels[i+5] = color
if (bits and 0b00000010 != 0) spritePixels[i+6] = color
if (bits and 0b00000001 != 0) spritePixels[i+7] = color
bits2Pixels(bits, spritePixels, i, color)
}
}
private fun renderCharacterMode(vicBank: Address, vicVMCSB: Int, multiColorMode: Boolean) {
if (multiColorMode) {
TODO("multicolor character mode")
} else {
// normal character mode
val screenAddress = vicBank+(vicVMCSB ushr 4) shl 10
val charsetAddress = (vicVMCSB and 0b00001110) shl 10
for (y in 0 until ScreenDefs.SCREEN_HEIGHT_CHARS) {
for (x in 0 until ScreenDefs.SCREEN_WIDTH_CHARS) {
val char = ram[screenAddress+x+y*ScreenDefs.SCREEN_WIDTH_CHARS].toInt()
val color = ram[0xd800+x+y*ScreenDefs.SCREEN_WIDTH_CHARS].toInt() // colors always at $d800
drawColoredChar(x, y, char, color, vicBank+charsetAddress)
}
// TODO multicolor character mode, for now, falls back to normal char mode
}
// normal character mode
val screenAddress = vicBank+((vicVMCSB ushr 4) shl 10)
val charsetAddress = (vicVMCSB and 0b00001110) shl 10
for (y in 0 until ScreenDefs.SCREEN_HEIGHT_CHARS) {
for (x in 0 until ScreenDefs.SCREEN_WIDTH_CHARS) {
val char = ram[screenAddress+x+y*ScreenDefs.SCREEN_WIDTH_CHARS].toInt()
val color = ram[0xd800+x+y*ScreenDefs.SCREEN_WIDTH_CHARS].toInt() // colors always at $d800
drawColoredChar(x, y, char, color, vicBank+charsetAddress)
}
}
}
@ -237,31 +232,44 @@ internal class Screen(private val chargenData: ByteArray, val ram: MemoryCompone
// and lies within the same 16K VIC bank as the screen character memory.
when (charsetAddr) {
0x1000, 0x1800, 0x9000, 0x9800 -> {
val charImage = getCharImage(char, color, charsetAddr and 0x0800 != 0)
val charImage = getCharFromROM(char, color, charsetAddr and 0x0800 != 0)
fullscreenG2d.drawImage(charImage, x*8+ScreenDefs.BORDER_SIZE, y*8+ScreenDefs.BORDER_SIZE, null)
}
else -> {
// TODO: currently custom charsets taken from RAM aren't supported yet (need to read the char pixels)
fullscreenG2d.drawImage(placeholderUserCharacter, x*8+ScreenDefs.BORDER_SIZE, y*8+ScreenDefs.BORDER_SIZE, null)
val charImg = getCharFromRAM(char, color, charsetAddr)
fullscreenG2d.drawImage(charImg, x*8+ScreenDefs.BORDER_SIZE, y*8+ScreenDefs.BORDER_SIZE, null)
}
}
}
// TODO: temporary placeholder for user-defined charset
private val placeholderUserCharacter: BufferedImage by lazy {
val img = fullscreenG2d.deviceConfiguration.createCompatibleImage(8, 8, BufferedImage.BITMASK)
with(img.graphics) {
color = Color.DARK_GRAY
fillRect(0, 0, 8, 8)
private val userCharacter = fullscreenG2d.deviceConfiguration.createCompatibleImage(8, 8, BufferedImage.BITMASK)
private fun getCharFromRAM(char: Int, color: Int, charsetAddr: Address): BufferedImage {
val chardefBytes = ram.getBlock(charsetAddr+char*8, 8)
val charPixels = (userCharacter.raster.dataBuffer as DataBufferInt).data
val rgb = ScreenDefs.colorPalette[color].rgb
val gfx = userCharacter.graphics
gfx.color = ScreenDefs.colorPalette[ram[0xd021]]
gfx.fillRect(0, 0, 8, 8)
for (y in 0..7) {
val bits = chardefBytes[y].toInt()
bits2Pixels(bits, charPixels, y*8, rgb)
}
for (x in 0..7) {
img.setRGB(x, x, Color.RED.rgb)
img.setRGB(7-x, x, Color.RED.rgb)
}
img
return userCharacter
}
private fun getCharImage(char: Int, color: Int, shifted: Boolean): BufferedImage {
private fun bits2Pixels(bits: Int, bitmap: IntArray, yoffset: Int, colorRgb: Int) {
if (bits and 0b10000000 != 0) bitmap[yoffset] = colorRgb
if (bits and 0b01000000 != 0) bitmap[yoffset+1] = colorRgb
if (bits and 0b00100000 != 0) bitmap[yoffset+2] = colorRgb
if (bits and 0b00010000 != 0) bitmap[yoffset+3] = colorRgb
if (bits and 0b00001000 != 0) bitmap[yoffset+4] = colorRgb
if (bits and 0b00000100 != 0) bitmap[yoffset+5] = colorRgb
if (bits and 0b00000010 != 0) bitmap[yoffset+6] = colorRgb
if (bits and 0b00000001 != 0) bitmap[yoffset+7] = colorRgb
}
private fun getCharFromROM(char: Int, color: Int, shifted: Boolean): BufferedImage {
val key = Triple(char, color, shifted)
fun makeCachedImage(): BufferedImage {

View File

@ -38,7 +38,7 @@ class VicII(startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemM
interruptStatusRegisterD019 = if (currentRasterLine == rasterIrqLine) {
// signal that current raster line is equal to the desired IRQ raster line
// schedule an IRQ as well if the raster interrupt is enabled
if ((ramBuffer[0x1a].toInt() and 1) != 0) cpu.irq()
if ((ramBuffer[0x1a].toInt() and 1) != 0) cpu.irqAsserted = true
interruptStatusRegisterD019 or 0b10000001
} else interruptStatusRegisterD019 and 0b11111110
}
@ -50,8 +50,8 @@ class VicII(startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemM
interruptStatusRegisterD019 = 0
}
override fun get(address: Address): UByte {
return when (val register = (address-startAddress) and 63) {
override operator fun get(offset: Int): UByte {
return when (val register = offset and 63) {
0x11 -> (0b00011011 or ((currentRasterLine and 0b100000000) ushr 1)).toShort()
0x12 -> {
(currentRasterLine and 255).toShort()
@ -61,8 +61,8 @@ class VicII(startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemM
}
}
override fun set(address: Address, data: UByte) {
val register = (address-startAddress) and 63
override operator fun set(offset: Int, data: UByte) {
val register = offset and 63
ramBuffer[register] = data
when (register) {
0x11 -> {

View File

@ -25,23 +25,37 @@ import kotlin.concurrent.scheduleAtFixedRate
*/
class C64Machine(title: String) : IVirtualMachine {
private val romsPath = determineRomPath()
private val chargenData = romsPath.resolve("chargen").toFile().readBytes()
private val basicData = romsPath.resolve("basic").toFile().readBytes()
private val kernalData = romsPath.resolve("kernal").toFile().readBytes()
override val bus = Bus()
private val chargenRom = Rom(0xd000, 0xdfff).also {
val chargenData = romsPath.resolve("chargen").toFile().readBytes()
it.load(chargenData)
}
private val basicRom = Rom(0xa000, 0xbfff).also {
val basicData = romsPath.resolve("basic").toFile().readBytes()
it.load(basicData)
}
private val kernalRom = Rom(0xe000, 0xffff).also {
val kernalData = romsPath.resolve("kernal").toFile().readBytes()
it.load(kernalData)
}
val cpuIoPort = CpuIoPort()
// This bus contains "mmu" logic to control the memory bank switching controlled by the 6510's io port in $00/$01.
// Therefore we provide it the various roms directly and not "connect" these to the bus in the default way.
override val bus = Bus6510(cpuIoPort, chargenRom, basicRom, kernalRom)
override val cpu = Cpu6502()
// the C64 has 64KB of RAM. Some of it may be banked out and replaced by ROM.
val ram = Ram(0x0000, 0xffff)
val vic = VicII(0xd000, 0xd3ff, cpu)
val cia1 = Cia(1, 0xdc00, 0xdcff, cpu)
val cia2 = Cia(2, 0xdd00, 0xddff, cpu)
val basicRom = Rom(0xa000, 0xbfff).also { it.load(basicData) }
val kernalRom = Rom(0xe000, 0xffff).also { it.load(kernalData) }
val cpuIoPort = CpuIoPort(cpu)
private val monitor = Monitor(bus, cpu)
private val debugWindow = DebugWindow(this)
private val hostDisplay = MainC64Window(title, chargenData, ram, cpu, cia1)
private val hostDisplay = MainC64Window(title, chargenRom, ram, cpu, cia1)
private var paused = false
init {
@ -49,13 +63,11 @@ class C64Machine(title: String) : IVirtualMachine {
cpu.addBreakpoint(0xffd8, ::breakpointKernelSave) // intercept SAVE subroutine in the kernal
cpu.breakpointForBRK = ::breakpointBRK
bus += basicRom
bus += kernalRom
bus += vic
bus += cia1
bus += cia2
bus += cpuIoPort
bus += ram
bus += ram // note: the ROMs are mapped depending on the cpu's io port
bus += cpu
bus.reset()
@ -75,7 +87,7 @@ class C64Machine(title: String) : IVirtualMachine {
val txttab = ram[0x2b]+256*ram[0x2c] // basic load address ($0801 usually)
val fnaddr = ram[0xbb]+256*ram[0xbc] // file name address
return if (fnlen > 0) {
val filename = (0 until fnlen).map { ram[fnaddr+it].toChar() }.joinToString("")
val filename = (0 until fnlen).map { ram[fnaddr+it].toInt().toChar() }.joinToString("")
val loadEndAddress = searchAndLoadFile(filename, fa, sa, txttab)
if (loadEndAddress != null) {
ram[0x90] = 0 // status OK
@ -96,7 +108,7 @@ class C64Machine(title: String) : IVirtualMachine {
val fromAddr = ram[cpu.regA]+256*ram[cpu.regA+1]
val endAddr = cpu.regX+256*cpu.regY
val data = (fromAddr..endAddr).map { ram[it].toByte() }.toByteArray()
var filename = (0 until fnlen).map { ram[fnaddr+it].toChar() }.joinToString("").toLowerCase()
var filename = (0 until fnlen).map { ram[fnaddr+it].toInt().toChar() }.joinToString("").lowercase()
if (!filename.endsWith(".prg")) filename += ".prg"
File(filename).outputStream().use {
it.write(fromAddr and 0xff)
@ -121,13 +133,13 @@ class C64Machine(title: String) : IVirtualMachine {
"$" -> {
// load the directory
val files = File(".").listFiles(FileFilter { it.isFile })!!.associate {
val name = it.nameWithoutExtension.toUpperCase()
val ext = it.extension.toUpperCase()
val name = it.nameWithoutExtension.uppercase()
val ext = it.extension.uppercase()
val fileAndSize = Pair(it, it.length())
if (name.isEmpty()) Pair(".$ext", "") to fileAndSize
else Pair(name, ext) to fileAndSize
}
val dirname = File(".").canonicalPath.substringAfterLast(File.separator).toUpperCase()
val dirname = File(".").canonicalPath.substringAfterLast(File.separator).uppercase()
val dirlisting = makeDirListing(dirname, files, basicLoadAddress)
ram.load(dirlisting, basicLoadAddress)
return basicLoadAddress+dirlisting.size-1
@ -135,7 +147,7 @@ class C64Machine(title: String) : IVirtualMachine {
else -> {
fun findHostFile(filename: String): String? {
val file = File(".").listFiles(FileFilter { it.isFile })?.firstOrNull {
it.name.toUpperCase() == filename
it.name.uppercase() == filename
}
return file?.name
}
@ -167,7 +179,7 @@ class C64Machine(title: String) : IVirtualMachine {
listing.add((address ushr 8).toShort())
listing.add((lineNumber and 0xff).toShort())
listing.add((lineNumber ushr 8).toShort())
listing.addAll(line.map { it.toShort() })
listing.addAll(line.map { it.code.toShort() })
listing.add(0)
}
addLine(0, "\u0012\"${dirname.take(16).padEnd(16)}\" 00 2A")
@ -186,24 +198,6 @@ class C64Machine(title: String) : IVirtualMachine {
return listing.toTypedArray()
}
private fun determineRomPath(): Path {
val candidates = listOf("./roms", "~/roms/c64", "~/roms", "~/.vice/C64")
candidates.forEach {
val path = Paths.get(expandUser(it))
if (path.toFile().isDirectory) return path
}
throw FileNotFoundException("no roms directory found, tried: $candidates")
}
private fun expandUser(path: String): String {
return when {
path.startsWith("~/") -> System.getProperty("user.home")+path.substring(1)
path.startsWith("~"+File.separatorChar) -> System.getProperty("user.home")+path.substring(1)
path.startsWith("~") -> throw UnsupportedOperationException("home dir expansion not implemented for other users")
else -> path
}
}
override fun loadFileInRam(file: File, loadAddress: Address?) {
if (file.extension == "prg" && (loadAddress == null || loadAddress == 0x0801)) ram.loadPrg(file.inputStream(), null)
else ram.load(file.readBytes(), loadAddress!!)
@ -222,6 +216,11 @@ class C64Machine(title: String) : IVirtualMachine {
while (cpu.instrCycles > 0) bus.clock()
}
override fun reset() {
bus.reset()
hostDisplay.reset()
}
override fun executeMonitorCommand(command: String) = monitor.command(command)
fun start() {
@ -229,11 +228,15 @@ class C64Machine(title: String) : IVirtualMachine {
debugWindow.updateCpu(cpu, bus)
}.start()
// we synchronise cpu cycles to the vertical blank of the Vic chip
// this should result in ~1 Mhz cpu speed
val timer = java.util.Timer("cpu-cycle", true)
timer.scheduleAtFixedRate(0, 1000L/VicII.framerate) {
// if(cpu.isLooping) {
// // cpu is jump looping, could do some sleeping here perhaps
// // but should still consider irqs occurring in the meantime...
// }
if (!paused) {
// we synchronise cpu cycles to the vertical blank of the Vic chip
// this should result in ~1 Mhz cpu speed
try {
while (vic.vsync) step()
while (!vic.vsync) step()
@ -252,6 +255,26 @@ class C64Machine(title: String) : IVirtualMachine {
}
}
fun determineRomPath(): Path {
val candidates = listOf("./roms", "~/roms/c64", "~/roms", "~/.vice/C64", "/usr/lib/vice/C64")
candidates.forEach {
val path = Paths.get(expandUser(it))
if (path.toFile().isDirectory) return path
}
throw FileNotFoundException("no roms directory found, tried: $candidates")
}
fun expandUser(path: String): String {
return when {
path.startsWith("~/") -> System.getProperty("user.home")+path.substring(1)
path.startsWith("~"+File.separatorChar) -> System.getProperty("user.home")+path.substring(1)
path.startsWith("~") -> throw UnsupportedOperationException("home dir expansion not implemented for other users")
else -> path
}
}
fun main() {
val machine = C64Machine("virtual Commodore-64 - using KSim65 v${Version.version}")
machine.start()

View File

@ -44,6 +44,7 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("Debugger - ksim65 v
it.disabledTextColor = Color.DARK_GRAY
it.font = Font(Font.MONOSPACED, Font.PLAIN, 12)
}
private val disassembler = Disassembler(vm.cpu)
init {
contentPane.layout = GridBagLayout()
@ -53,8 +54,6 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("Debugger - ksim65 v
val gc = GridBagConstraints()
gc.insets = Insets(2, 2, 2, 2)
gc.anchor = GridBagConstraints.EAST
gc.gridx = 0
gc.gridy = 0
val cyclesLb = JLabel("cycles")
val speedKhzLb = JLabel("speed (kHz)")
val regAlb = JLabel("A")
@ -64,13 +63,25 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("Debugger - ksim65 v
val regPClb = JLabel("PC")
val regPlb = JLabel("Status")
val disassemLb = JLabel("Instruction")
listOf(cyclesLb, speedKhzLb, regAlb, regXlb, regYlb, regSPlb, regPClb, disassemLb, regPlb).forEach {
cpuPanel.add(it, gc)
gc.gridy++
}
cpuPanel.add(cyclesLb, gc.update(gridx=0, gridy=0))
cpuPanel.add(speedKhzLb, gc.update(gridx=5, gridy=0))
cpuPanel.add(regAlb, gc.update(gridx=0, gridy=1))
cpuPanel.add(regXlb, gc.update(gridx=2, gridy=1))
cpuPanel.add(regYlb, gc.update(gridx=4, gridy=1))
cpuPanel.add(regPClb, gc.update(gridx=0, gridy=2))
cpuPanel.add(regSPlb, gc.update(gridx=2, gridy=2))
cpuPanel.add(regPlb, gc.update(gridx=0, gridy=3))
cpuPanel.add(disassemLb, gc.update(gridx=0, gridy=4))
gc.anchor = GridBagConstraints.WEST
gc.gridx = 1
gc.gridy = 0
cpuPanel.add(cyclesTf, gc.update(gridx=1, gridy=0, gridwidth = 3))
cpuPanel.add(speedKhzTf, gc.update(gridx=6, gridy=0))
cpuPanel.add(regAtf, gc.update(gridx=1, gridy=1))
cpuPanel.add(regXtf, gc.update(gridx=3, gridy=1))
cpuPanel.add(regYtf, gc.update(gridx=5, gridy=1))
cpuPanel.add(regPCtf, gc.update(gridx=1, gridy=2))
cpuPanel.add(regSPtf, gc.update(gridx=3, gridy=2))
cpuPanel.add(regPtf, gc.update(gridx=1, gridy=3, gridwidth=2))
cpuPanel.add(disassemTf, gc.update(gridx=1, gridy=4, gridwidth=5))
listOf(cyclesTf, speedKhzTf, regAtf, regXtf, regYtf, regSPtf, regPCtf, disassemTf, regPtf).forEach {
it.font = Font(Font.MONOSPACED, Font.PLAIN, 14)
it.disabledTextColor = Color.DARK_GRAY
@ -81,8 +92,6 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("Debugger - ksim65 v
it.border = BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY),
BorderFactory.createEmptyBorder(2, 2, 2, 2))
}
cpuPanel.add(it, gc)
gc.gridy++
}
val buttonPanel = JPanel(FlowLayout())
@ -115,7 +124,7 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("Debugger - ksim65 v
val monitorPanel = JPanel()
monitorPanel.layout = BoxLayout(monitorPanel, BoxLayout.Y_AXIS)
monitorPanel.border = BorderFactory.createTitledBorder("Built-in Monitor")
val output = JTextArea(6, 80)
val output = JTextArea(10, 80)
output.font = Font(Font.MONOSPACED, Font.PLAIN, 14)
output.isEditable = false
val outputScroll = JScrollPane(output)
@ -173,6 +182,7 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("Debugger - ksim65 v
}
"reset" -> {
vm.reset()
vm.bus.reset()
updateCpu(vm.cpu, vm.bus)
}
@ -190,8 +200,8 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("Debugger - ksim65 v
pauseBt.actionCommand = "pause"
pauseBt.text = "Pause"
}
"irq" -> vm.cpu.irq()
"nmi" -> vm.cpu.nmi()
"irq" -> vm.cpu.irqAsserted = true
"nmi" -> vm.cpu.nmiAsserted = true
"quit" -> {
dispatchEvent(WindowEvent(this, WindowEvent.WINDOW_CLOSING))
}
@ -207,8 +217,11 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("Debugger - ksim65 v
regPtf.text = "NV-BDIZC\n"+state.P.asInt().toString(2).padStart(8, '0')
regPCtf.text = hexW(state.PC)
regSPtf.text = hexB(state.SP)
val memory = bus.memoryComponentFor(state.PC)
disassemTf.text = cpu.disassembleOneInstruction(memory.data, state.PC, memory.startAddress).first.substringAfter(' ').trim()
val memory = listOf(bus[state.PC], bus[state.PC+1], bus[state.PC+2]).toTypedArray()
val disassem = disassembler.disassembleOneInstruction(memory, 0, state.PC).first.substringAfter(' ').trim()
disassemTf.text = disassem
if (zeropageTf.isVisible || stackpageTf.isVisible) {
val pages = vm.getZeroAndStackPages()
@ -231,3 +244,13 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("Debugger - ksim65 v
speedKhzTf.text = "%.1f".format(cpu.averageSpeedKhzSinceReset)
}
}
private fun GridBagConstraints.update(gridx: Int, gridy: Int, gridwidth: Int?=null): GridBagConstraints {
val gc = this.clone() as GridBagConstraints
gc.gridx = gridx
gc.gridy = gridy
if(gridwidth!=null)
gc.gridwidth=gridwidth
return gc
}

View File

@ -1,57 +1,27 @@
package razorvine.examplemachines
import razorvine.fonts.PsfFont
import razorvine.ksim65.*
import java.awt.*
import java.awt.event.*
import java.awt.image.BufferedImage
import java.util.*
import javax.imageio.ImageIO
import javax.swing.*
import javax.swing.event.MouseInputListener
/**
* Define a monochrome screen that can display 640x480 pixels
* and/or 80x30 characters (these are 8x16 pixels).
* Define a monochrome screen that can display 80x30 charaacters
* (usually equivalent to 640x480 pixels, but depends on the font size)
*/
object ScreenDefs {
const val SCREEN_WIDTH_CHARS = 80
const val SCREEN_HEIGHT_CHARS = 30
const val SCREEN_WIDTH = SCREEN_WIDTH_CHARS*8
const val SCREEN_HEIGHT = SCREEN_HEIGHT_CHARS*16
const val PIXEL_SCALING = 1.5
const val COLUMNS = 80
const val ROWS = 30
const val BORDER_SIZE = 32
val BG_COLOR = Color(0, 10, 20)
val FG_COLOR = Color(200, 255, 230)
val BORDER_COLOR = Color(20, 30, 40)
val Characters = loadCharacters()
private fun loadCharacters(): Array<BufferedImage> {
val img = ImageIO.read(javaClass.getResourceAsStream("/charset/unscii8x16.png"))
val charactersImage = BufferedImage(img.width, img.height, BufferedImage.TYPE_INT_ARGB)
charactersImage.createGraphics().drawImage(img, 0, 0, null)
val black = Color(0, 0, 0).rgb
val foreground = FG_COLOR.rgb
val nopixel = Color(0, 0, 0, 0).rgb
for (y in 0 until charactersImage.height) {
for (x in 0 until charactersImage.width) {
val col = charactersImage.getRGB(x, y)
if (col == black) charactersImage.setRGB(x, y, nopixel)
else charactersImage.setRGB(x, y, foreground)
}
}
val numColumns = charactersImage.width/8
val charImages = (0..255).map {
val charX = it%numColumns
val charY = it/numColumns
charactersImage.getSubimage(charX*8, charY*16, 8, 16)
}
return charImages.toTypedArray()
}
}
private class BitmapScreenPanel : JPanel() {
@ -61,15 +31,21 @@ private class BitmapScreenPanel : JPanel() {
private var cursorX: Int = 0
private var cursorY: Int = 0
private var cursorState: Boolean = false
private val screenFont = PsfFont("spleen-12x24") // nice fonts: sun12x22, iso01-12x22, ter-124b, spleen-12x24, default8x16
private val pixelScaling: Double = if(screenFont.width <= 8) 1.5 else 1.0
private val screenFontImage: BufferedImage
init {
println("SCREENFONT WIDTH: ${screenFont.width}")
val ge = GraphicsEnvironment.getLocalGraphicsEnvironment()
val gd = ge.defaultScreenDevice.defaultConfiguration
image = gd.createCompatibleImage(ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT, Transparency.OPAQUE)
image = gd.createCompatibleImage(ScreenDefs.COLUMNS*screenFont.width, ScreenDefs.ROWS*screenFont.height, Transparency.OPAQUE)
g2d = image.graphics as Graphics2D
screenFontImage = screenFont.convertToImage(g2d, ScreenDefs.FG_COLOR)
val size = Dimension((image.width*ScreenDefs.PIXEL_SCALING).toInt(),
(image.height*ScreenDefs.PIXEL_SCALING).toInt())
val size = Dimension((image.width*pixelScaling).toInt(),
(image.height*pixelScaling).toInt())
minimumSize = size
maximumSize = size
preferredSize = size
@ -82,13 +58,13 @@ private class BitmapScreenPanel : JPanel() {
override fun paint(graphics: Graphics) {
val g2d = graphics as Graphics2D
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
g2d.drawImage(image, 0, 0, (image.width*ScreenDefs.PIXEL_SCALING).toInt(),
(image.height*ScreenDefs.PIXEL_SCALING).toInt(), null)
g2d.drawImage(image, 0, 0, (image.width*pixelScaling).toInt(),
(image.height*pixelScaling).toInt(), null)
if (cursorState) {
val scx = (cursorX*ScreenDefs.PIXEL_SCALING*8).toInt()
val scy = (cursorY*ScreenDefs.PIXEL_SCALING*16).toInt()
val scw = (8*ScreenDefs.PIXEL_SCALING).toInt()
val sch = (16*ScreenDefs.PIXEL_SCALING).toInt()
val scx = (cursorX*pixelScaling*screenFont.width).toInt()
val scy = (cursorY*pixelScaling*screenFont.height).toInt()
val scw = (screenFont.width*pixelScaling).toInt()
val sch = (screenFont.height*pixelScaling).toInt()
g2d.setXORMode(Color.CYAN)
g2d.fillRect(scx, scy, scw, sch)
g2d.setPaintMode()
@ -98,7 +74,7 @@ private class BitmapScreenPanel : JPanel() {
fun clearScreen() {
g2d.background = ScreenDefs.BG_COLOR
g2d.clearRect(0, 0, ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT)
g2d.clearRect(0, 0, ScreenDefs.COLUMNS*screenFont.width, ScreenDefs.ROWS*screenFont.height)
cursorPos(0, 0)
}
@ -110,20 +86,26 @@ private class BitmapScreenPanel : JPanel() {
fun getPixel(x: Int, y: Int) = image.getRGB(x, y) != ScreenDefs.BG_COLOR.rgb
fun setChar(x: Int, y: Int, character: Char) {
g2d.clearRect(8*x, 16*y, 8, 16)
val coloredImage = ScreenDefs.Characters[character.toInt()]
g2d.drawImage(coloredImage, 8*x, 16*y, null)
val charnum = character.code
val cx = charnum % (screenFontImage.width/screenFont.width)
val cy = charnum / (screenFontImage.width/screenFont.width)
g2d.clearRect(x*screenFont.width, y*screenFont.height, screenFont.width, screenFont.height)
g2d.drawImage(screenFontImage, x*screenFont.width, y*screenFont.height, (x+1)*screenFont.width,
(y+1)*screenFont.height, cx*screenFont.width, cy*screenFont.height,
(cx+1)*screenFont.width, (cy+1)*screenFont.height, null)
}
fun scrollUp() {
g2d.copyArea(0, 16, ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT-16, 0, -16)
g2d.copyArea(0, screenFont.height,
ScreenDefs.COLUMNS*screenFont.width, (ScreenDefs.ROWS-1)*screenFont.height,
0, -screenFont.height)
g2d.background = ScreenDefs.BG_COLOR
g2d.clearRect(0, ScreenDefs.SCREEN_HEIGHT-16, ScreenDefs.SCREEN_WIDTH, 16)
g2d.clearRect(0, (ScreenDefs.ROWS-1)*screenFont.height, ScreenDefs.COLUMNS*screenFont.width, screenFont.height)
}
fun mousePixelPosition(): Point? {
val pos = mousePosition ?: return null
return Point((pos.x/ScreenDefs.PIXEL_SCALING).toInt(), (pos.y/ScreenDefs.PIXEL_SCALING).toInt())
return Point((pos.x/pixelScaling).toInt(), (pos.y/pixelScaling).toInt())
}
fun cursorPos(x: Int, y: Int) {
@ -242,4 +224,8 @@ class MainWindow(title: String) : JFrame(title), KeyListener, MouseInputListener
else keyboardBuffer.pop()
}
fun reset() {
// when the reset button is pressed
}
}

View File

@ -21,7 +21,7 @@ class EhBasicMachine(title: String) {
val rom = Rom(0xc000, 0xffff).also { it.load(javaClass.getResourceAsStream("/ehbasic_C000.bin").readBytes()) }
private val hostDisplay = MainWindow(title)
private val display = Display(0xd000, 0xd00a, hostDisplay, ScreenDefs.SCREEN_WIDTH_CHARS, ScreenDefs.SCREEN_HEIGHT_CHARS)
private val display = Display(0xd000, 0xd00a, hostDisplay, ScreenDefs.COLUMNS, ScreenDefs.ROWS)
private val keyboard = Keyboard(0xd400, 0xd400, hostDisplay)
private var paused = false
@ -53,7 +53,7 @@ class EhBasicMachine(title: String) {
Thread.sleep(200)
} else {
try {
repeat(400) { step() }
repeat(500) { step() }
} catch (rx: RuntimeException) {
JOptionPane.showMessageDialog(hostDisplay, "Run time error: $rx", "Error during execution", JOptionPane.ERROR_MESSAGE)
break
@ -61,7 +61,7 @@ class EhBasicMachine(title: String) {
JOptionPane.showMessageDialog(hostDisplay, "Run time error: $ex", "Error during execution", JOptionPane.ERROR_MESSAGE)
break
}
Thread.sleep(1)
Thread.sleep(2)
}
}
}

View File

@ -20,7 +20,7 @@ class VirtualMachine(title: String) : IVirtualMachine {
private val monitor = Monitor(bus, cpu)
private val debugWindow = DebugWindow(this)
private val hostDisplay = MainWindow(title)
private val display = Display(0xd000, 0xd00a, hostDisplay, ScreenDefs.SCREEN_WIDTH_CHARS, ScreenDefs.SCREEN_HEIGHT_CHARS)
private val display = Display(0xd000, 0xd00a, hostDisplay, ScreenDefs.COLUMNS, ScreenDefs.ROWS)
private val mouse = Mouse(0xd300, 0xd305, hostDisplay)
private val keyboard = Keyboard(0xd400, 0xd400, hostDisplay)
private var paused = false
@ -65,6 +65,11 @@ class VirtualMachine(title: String) : IVirtualMachine {
while (cpu.instrCycles > 0) bus.clock()
}
override fun reset() {
bus.reset()
hostDisplay.reset()
}
override fun executeMonitorCommand(command: String) = monitor.command(command)
fun start() {
@ -79,7 +84,7 @@ class VirtualMachine(title: String) : IVirtualMachine {
Thread.sleep(200)
} else {
try {
repeat(400) { step() }
repeat(500) { step() }
} catch (rx: RuntimeException) {
JOptionPane.showMessageDialog(hostDisplay, "Run time error: $rx", "Error during execution", JOptionPane.ERROR_MESSAGE)
break
@ -87,7 +92,7 @@ class VirtualMachine(title: String) : IVirtualMachine {
JOptionPane.showMessageDialog(hostDisplay, "Run time error: $ex", "Error during execution", JOptionPane.ERROR_MESSAGE)
break
}
Thread.sleep(1)
Thread.sleep(10)
}
}
}

View File

@ -0,0 +1,138 @@
package razorvine.fonts
import java.awt.Color
import java.awt.Graphics2D
import java.awt.Transparency
import java.awt.image.BufferedImage
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.util.zip.GZIPInputStream
class PsfFont(name: String) {
// font format info: https://www.win.tue.nl/~aeb/linux/kbd/font-formats-1.html
val numChars: Int
val bytesPerChar: Int
val height: Int
val width: Int
private val hasUnicodeTable: Boolean
private val rawBitmaps: List<ByteArray>
init {
val data: ByteArray
val fontsDirectory = "/usr/share/kbd/consolefonts"
var stream = javaClass.getResourceAsStream("/charset/$name.psfu.gz") ?:
javaClass.getResourceAsStream("/charset/$name.psf.gz") ?:
(if(File("$fontsDirectory/$name.psfu.gz").exists()) FileInputStream("$fontsDirectory/$name.psfu.gz") else null ) ?:
(if(File("$fontsDirectory/$name.psf.gz").exists()) FileInputStream("$fontsDirectory/$name.psf.gz") else null ) ?:
(if(File("$fontsDirectory/$name.fnt.gz").exists()) FileInputStream("$fontsDirectory/$name.fnt.gz") else null )
if(stream==null) {
stream = javaClass.getResourceAsStream("/charset/$name.psfu") ?:
javaClass.getResourceAsStream("/charset/$name.psf") ?:
(if(File("$fontsDirectory/$name.psfu").exists()) FileInputStream("$fontsDirectory/$name.psfu") else null ) ?:
(if(File("$fontsDirectory/$name.psf").exists()) FileInputStream("$fontsDirectory/$name.psf") else null ) ?:
(if(File("$fontsDirectory/$name.fnt").exists()) FileInputStream("$fontsDirectory/$name.fnt") else null ) ?:
throw IOException("no such font: $name")
data = stream.readBytes()
} else {
GZIPInputStream(stream).use { data = it.readBytes() }
}
stream.close()
if (data[0] == 0x36.toByte() && data[1] == 0x04.toByte()) {
// continue reading PSF1 font
val mode = data[2].toInt()
numChars = if (mode and 1 != 0) 512 else 256
bytesPerChar = data[3].toInt()
hasUnicodeTable = mode and 2 != 0
height = bytesPerChar
width = 8
rawBitmaps = (0..numChars).map {
data.sliceArray(3+it*bytesPerChar..3+(it+1)*bytesPerChar)
}
// ignore unicode table for now: val table = stream.readAllBytes()
} else {
if (data[0] == 0x72.toByte() && data[1] == 0xb5.toByte() && data[2] == 0x4a.toByte() && data[3] == 0x86.toByte()) {
// continue reading PSF2 font
// skip the version val version = makeInt(data, 4)
val headersize = makeInt(data, 8)
val flags = makeInt(data, 12)
hasUnicodeTable = flags and 1 != 0
numChars = makeInt(data, 16)
bytesPerChar = makeInt(data, 20)
height = makeInt(data, 24)
width = makeInt(data, 28)
rawBitmaps = (0..numChars).map {
data.sliceArray(headersize+it*bytesPerChar..headersize+(it+1)*bytesPerChar)
}
} else {
hasUnicodeTable = false
numChars = 0
bytesPerChar = 0
height = 0
width = 0
rawBitmaps = emptyList()
}
}
}
fun convertToImage(gfx: Graphics2D, textColor: Color): BufferedImage {
// create a single image with all the characters in a vertical column from top to bottom.
val bitmap = gfx.deviceConfiguration.createCompatibleImage((width+7) and 0b11111000, height*numChars, Transparency.BITMASK)
val bytesHoriz = (width+7)/8
val color = textColor.rgb
val nopixel = Color(0, 0, 0, 0).rgb
for (char in 0 until numChars) {
for (b in 0 until bytesPerChar) {
val c = rawBitmaps[char][b].toInt()
val ix = 8*(b%bytesHoriz)
val iy = b/bytesHoriz+char*height
bitmap.setRGB(ix, iy, if (c and 0b10000000 != 0) color else nopixel)
bitmap.setRGB(ix+1, iy, if (c and 0b01000000 != 0) color else nopixel)
bitmap.setRGB(ix+2, iy, if (c and 0b00100000 != 0) color else nopixel)
bitmap.setRGB(ix+3, iy, if (c and 0b00010000 != 0) color else nopixel)
bitmap.setRGB(ix+4, iy, if (c and 0b00001000 != 0) color else nopixel)
bitmap.setRGB(ix+5, iy, if (c and 0b00000100 != 0) color else nopixel)
bitmap.setRGB(ix+6, iy, if (c and 0b00000010 != 0) color else nopixel)
bitmap.setRGB(ix+7, iy, if (c and 0b00000001 != 0) color else nopixel)
}
}
return bitmap
}
private fun makeInt(bytes: ByteArray, offset: Int) =
makeInt(bytes[offset], bytes[offset+1], bytes[offset+2], bytes[offset+3])
private fun makeInt(b0: Byte, b1: Byte, b2: Byte, b3: Byte) =
b0.toInt() or (b1.toInt() shl 8) or (b2.toInt() shl 16) or (b3.toInt() shl 24)
}
// private fun loadFallbackCharacters(): Array<BufferedImage> {
// val img = ImageIO.read(javaClass.getResourceAsStream("/charset/unscii8x16.png"))
// val charactersImage = BufferedImage(img.width, img.height, BufferedImage.TYPE_INT_ARGB)
// charactersImage.createGraphics().drawImage(img, 0, 0, null)
//
// val black = Color(0, 0, 0).rgb
// val foreground = FG_COLOR.rgb
// val nopixel = Color(0, 0, 0, 0).rgb
// for (y in 0 until charactersImage.height) {
// for (x in 0 until charactersImage.width) {
// val col = charactersImage.getRGB(x, y)
// if (col == black) charactersImage.setRGB(x, y, nopixel)
// else charactersImage.setRGB(x, y, foreground)
// }
// }
//
// val numColumns = charactersImage.width/8
// val charImages = (0..255).map {
// val charX = it%numColumns
// val charY = it/numColumns
// charactersImage.getSubimage(charX*8, charY*16, 8, 16)
// }
//
// return charImages.toTypedArray()
// }

View File

@ -0,0 +1,237 @@
package razorvine.ksim65
import razorvine.ksim65.components.Address
import razorvine.ksim65.components.MemMappedComponent
class Assembler(cpu: Cpu6502, val memory: MemMappedComponent, initialStartAddress: Address? = null) {
companion object {
fun parseRelativeToPC(relative: String, currentAddress: Int): Int {
val rest = relative.substring(1).trim()
if(rest.isNotEmpty()) {
return when(rest[0]) {
'-' -> currentAddress-parseNumber(rest.substring(1))
'+' -> currentAddress+parseNumber(rest.substring(1))
else -> throw NumberFormatException("invalid address syntax")
}
}
return currentAddress
}
fun parseNumber(number: String, decimalFirst: Boolean = false): Int {
val num = number.trim()
if (num.isBlank()) return 0
if (decimalFirst && num[0].isDigit()) return num.toInt(10)
return when (num[0]) {
'$' -> num.substring(1).trimStart().toInt(16)
'#' -> num.substring(1).trimStart().toInt(10)
'%' -> num.substring(1).trimStart().toInt(2)
else -> num.toInt(16)
}
}
}
private var startAddress = initialStartAddress ?: 0
private var assembledSize = 0
private val instructions by lazy {
val instr = cpu.instructions.withIndex().associate {
Pair(it.value.mnemonic, it.value.mode) to it.index
}.toMutableMap()
instr[Pair("nop", Cpu6502.AddrMode.Imp)] = 0xea
instr.toMap()
}
class Result(val success: Boolean, val error: String, val startAddress: Address, val numBytes: Int)
fun assemble(lines: Iterable<String>): Result {
for(line in lines) {
val result = assemble(line)
if(!result.success)
return result
assembledSize += result.numBytes
}
return Result(true, "", startAddress, assembledSize)
}
fun assemble(line: String): Result {
/*
The command is a line of the form:
"<address> <instruction> [<arguments>]"
" <instruction> [<arguments>]"
"* = <address>"
*/
var args = line.trim().split(' ')
if(args.isEmpty() || args.size == 1 && args[0] == "")
return Result(true, "", startAddress, 0)
if(args[0].startsWith("*=") && args.size==1) {
startAddress = parseNumber(args[0].substring(2))
return Result(true, "", startAddress, 0)
}
else if(args[0] == "*" && args[1] == "=") {
startAddress = parseNumber(args[2])
return Result(true, "", startAddress, 0)
} else {
// line with an instruction, may be preceded by a 4 or 5 char address
if(args[0].length == 4 || args[0].length==5) {
if(args.size!=2 && args.size !=3)
return Result(false, "syntax error", startAddress, 0)
startAddress = parseNumber(args[0])
args = args.drop(1)
}
}
val instructionSize: Int
val mnemonic = args[0].lowercase().trim()
when (args.size) {
1 -> {
// implied or acc
instructionSize = 1
var instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Imp)]
if (instruction == null) instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Acc)]
if (instruction == null) return Result(false, "invalid instruction", this.startAddress, 0)
memory[startAddress+assembledSize] = instruction.toShort()
}
2 -> {
val arg = args[1]
when {
arg.startsWith('#') -> {
// immediate
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Imm)] ?: return Result(false, "invalid instruction",
this.startAddress, 0)
memory[startAddress+assembledSize] = instruction.toShort()
memory[startAddress+assembledSize+1] = parseNumber(arg.substring(1), decimalFirst = true).toShort()
instructionSize = 2
}
arg.startsWith("(") && arg.endsWith(",x)") -> {
// indirect X
val indAddress = try {
parseNumber(arg.substring(1, arg.length-3))
} catch (x: NumberFormatException) {
return Result(false, "invalid instruction", this.startAddress, 0)
}
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.IzX)] ?: return Result(false, "invalid instruction",
this.startAddress, 0)
memory[startAddress+assembledSize] = instruction.toShort()
memory[startAddress+assembledSize+1] = indAddress.toShort()
instructionSize = 2
}
arg.startsWith("(") && arg.endsWith("),y") -> {
// indirect Y
val indAddress = try {
parseNumber(arg.substring(1, arg.length-3))
} catch (x: NumberFormatException) {
return Result(false, "invalid instruction", this.startAddress, 0)
}
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.IzY)] ?: return Result(false, "invalid instruction",
this.startAddress, 0)
memory[startAddress+assembledSize] = instruction.toShort()
memory[startAddress+assembledSize+1] = indAddress.toShort()
instructionSize = 2
}
arg.endsWith(",x") -> {
// indexed X or zpIndexed X
val indAddress = try {
parseNumber(arg.substring(1, arg.length-2))
} catch (x: NumberFormatException) {
return Result(false, "invalid instruction", this.startAddress, 0)
}
instructionSize = if (indAddress <= 255) {
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.ZpX)] ?: return Result(false, "invalid instruction",
this.startAddress, 0)
memory[startAddress+assembledSize] = instruction.toShort()
memory[startAddress+assembledSize+1] = indAddress.toShort()
2
} else {
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.AbsX)] ?: return Result(false, "invalid instruction",
this.startAddress, 0)
memory[startAddress+assembledSize] = instruction.toShort()
memory[startAddress+assembledSize+1] = (indAddress and 255).toShort()
memory[startAddress+assembledSize+2] = (indAddress ushr 8).toShort()
3
}
}
arg.endsWith(",y") -> {
// indexed Y or zpIndexed Y
val indAddress = try {
parseNumber(arg.substring(1, arg.length-2))
} catch (x: NumberFormatException) {
return Result(false, "invalid instruction", this.startAddress, 0)
}
instructionSize = if (indAddress <= 255) {
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.ZpY)] ?: return Result(false, "invalid instruction",
this.startAddress, 0)
memory[startAddress+assembledSize] = instruction.toShort()
memory[startAddress+assembledSize+1] = indAddress.toShort()
2
} else {
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.AbsY)] ?: return Result(false, "invalid instruction",
this.startAddress, 0)
memory[startAddress+assembledSize] = instruction.toShort()
memory[startAddress+assembledSize+1] = (indAddress and 255).toShort()
memory[startAddress+assembledSize+2] = (indAddress ushr 8).toShort()
3
}
}
arg.endsWith(")") -> {
// indirect (jmp)
val indAddress = try {
parseNumber(arg.substring(1, arg.length-1))
} catch (x: NumberFormatException) {
return Result(false, "invalid instruction", this.startAddress, 0)
}
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Ind)]
?: return Result(false, "invalid instruction", this.startAddress, 0)
memory[startAddress+assembledSize] = instruction.toShort()
memory[startAddress+assembledSize+1] = (indAddress and 255).toShort()
memory[startAddress+assembledSize+2] = (indAddress ushr 8).toShort()
instructionSize = 3
}
else -> {
val instr = instructions[Pair(mnemonic, Cpu6502.AddrMode.Rel)]
if (instr != null) {
// relative address
val rel = try {
parseRelativeToPC(arg, startAddress)
} catch (x: NumberFormatException) {
return Result(false, "invalid numeral", this.startAddress, 0)
}
memory[startAddress+assembledSize] = instr.toShort()
memory[startAddress+assembledSize+1] = (rel-startAddress-2 and 255).toShort()
instructionSize = 2
} else {
// absolute or absZp
val absAddress = try {
if(arg.startsWith('*')) parseRelativeToPC(arg, startAddress) else parseNumber(arg)
} catch (x: NumberFormatException) {
return Result(false, "invalid numeral", this.startAddress, 0)
}
val zpInstruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Zp)]
instructionSize = if (absAddress <= 255 && zpInstruction != null) {
memory[startAddress+assembledSize] = zpInstruction.toShort()
memory[startAddress+assembledSize+1] = absAddress.toShort()
2
} else {
val absInstr = instructions[Pair(mnemonic, Cpu6502.AddrMode.Abs)] ?: return Result(false, "invalid instruction",
this.startAddress, 0)
memory[startAddress+assembledSize] = absInstr.toShort()
memory[startAddress+assembledSize+1] = (absAddress and 255).toShort()
memory[startAddress+assembledSize+2] = (absAddress ushr 8).toShort()
3
}
}
}
}
}
else ->
return Result(false, "syntax error", this.startAddress, 0)
}
return Result(true, "", this.startAddress, instructionSize)
}
}

View File

@ -12,7 +12,7 @@ import razorvine.ksim65.components.*
* NOTE: currently the bus address mapping is STATIC: there is no possibility for Bank-switching.
* (such as what the C-64 has; the ability to swap ROMs in and out of the address space).
*/
class Bus {
open class Bus {
private val allComponents = mutableListOf<BusComponent>()
private val memComponents = mutableListOf<MemMappedComponent>()
@ -42,10 +42,10 @@ class Bus {
* The first registered memory mapped component that listens to that address, will respond.
* If no component is available, some CPUs generate a BUS ERROR but we return 0xff instead.
*/
fun read(address: Address): UByte {
open fun read(address: Address): UByte {
memComponents.forEach {
if (address >= it.startAddress && address <= it.endAddress) {
val data = it[address]
val data = it[address - it.startAddress]
require(data in 0..255) { "data at address $address must be a byte 0..255, but is $data" }
return data
}
@ -57,13 +57,15 @@ class Bus {
* Write a data byte to the given address.
* All memory mapped components that are mapped to the address, will receive the data.
*/
fun write(address: Address, data: UByte) {
open fun write(address: Address, data: UByte) {
require(data in 0..255) { "data written to address $address must be a byte 0..255" }
memComponents.forEach {
if (address >= it.startAddress && address <= it.endAddress) it[address] = data
if (address >= it.startAddress && address <= it.endAddress)
it[address-it.startAddress] = data
}
}
fun memoryComponentFor(address: Address) =
memComponents.first { it is MemoryComponent && address >= it.startAddress && address <= it.endAddress } as MemoryComponent
}

File diff suppressed because it is too large Load Diff

View File

@ -17,20 +17,20 @@ class Cpu65C02 : Cpu6502() {
/**
* Process once clock cycle in the cpu
* Use this if goal is cycle-perfect emulation.
* Use this if you need cycle-perfect instruction timing simulation.
*/
override fun clock() {
when (waiting) {
Wait.Normal -> super.clock()
Wait.Waiting -> {
if (pendingInterrupt != null) {
if (nmiAsserted || irqAsserted) {
// continue execution after hardware interrupt
waiting = Wait.Normal
instrCycles = 1
}
}
Wait.Stopped -> {
if (pendingInterrupt != null) {
if (nmiAsserted || irqAsserted) {
// jump to reset vector after hardware interrupt
regPC = readWord(RESET_vector)
}
@ -40,7 +40,7 @@ class Cpu65C02 : Cpu6502() {
/**
* Execute one single complete instruction.
* Use this when the goal is emulation performance and not a cycle perfect system.
* Use this when you don't care about clock cycle instruction timing simulation.
*/
override fun step() {
totalCycles += instrCycles
@ -103,7 +103,7 @@ class Cpu65C02 : Cpu6502() {
}
override fun dispatchOpcode(opcode: Int): Boolean {
when (opcode) {
return when (opcode) {
0x00 -> iBrk()
0x01 -> iOra()
0x02 -> iNop()
@ -360,9 +360,8 @@ class Cpu65C02 : Cpu6502() {
0xfd -> iSbc()
0xfe -> iInc()
0xff -> iBbs7()
else -> { /* can't occur */ }
else -> false /* can't occur */
}
return false // TODO determine if instructions can cause extra clock cycle
}
// opcode list: http://www.oxyron.de/html/opcodesc02.html
@ -624,33 +623,36 @@ class Cpu65C02 : Cpu6502() {
/* fe */ Instruction("inc", AddrMode.AbsX, 7),
/* ff */ Instruction("bbs7", AddrMode.Zpr, 5)).toTypedArray()
override fun iBrk() {
// handle BRK ('software interrupt') or a real hardware IRQ
val nmi = pendingInterrupt == Interrupt.NMI
if (pendingInterrupt != null) {
pushStackAddr(regPC-1)
} else {
regPC++
pushStackAddr(regPC)
}
regP.B = pendingInterrupt == null
override fun iBrk(): Boolean {
// handle BRK ('software interrupt')
regPC++
pushStackAddr(regPC)
regP.B = true
pushStack(regP)
regP.I = true // interrupts are now disabled
regP.D = false // this is different from NMOS 6502
regPC = readWord(if (nmi) NMI_vector else IRQ_vector)
pendingInterrupt = null
regPC = readWord(IRQ_vector)
// TODO prevent NMI from triggering immediately after IRQ/BRK... how does that work exactly?
return false
}
override fun iBit() {
override fun handleInterrupt() {
super.handleInterrupt()
regP.D = false // this is different from NMOS 6502
}
override fun iBit(): Boolean {
val data = getFetched()
regP.Z = (regA and data) == 0
if (currentInstruction.mode != AddrMode.Imm) {
regP.V = (data and 0b01000000) != 0
regP.N = (data and 0b10000000) != 0
}
return false
}
override fun iAdc() {
override fun iAdc(): Boolean {
val value = getFetched()
if (regP.D) {
// BCD add
@ -679,13 +681,14 @@ class Cpu65C02 : Cpu6502() {
regP.C = tmp > 0xff
regA = tmp and 0xff
}
return false
}
override fun iSbc() {
override fun iSbc(operandOverride: Int?): Boolean {
// see http://www.6502.org/tutorials/decimal_mode.html
// and https://sourceforge.net/p/vice-emu/code/HEAD/tree/trunk/vice/src/65c02core.c#l1205
// (the implementation below is based on the code used by Vice)
val value = getFetched()
val value = operandOverride ?: getFetched()
var tmp = (regA-value-if (regP.C) 0 else 1) and 0xffff
regP.V = (regA xor tmp) and (regA xor value) and 0b10000000 != 0
if (regP.D) {
@ -697,230 +700,323 @@ class Cpu65C02 : Cpu6502() {
regP.Z = (tmp and 0xff) == 0
regP.N = (tmp and 0b10000000) != 0
regA = tmp and 0xff
return false
}
override fun iDec() {
if (currentInstruction.mode == AddrMode.Acc) {
override fun iDec(): Boolean {
return if (currentInstruction.mode == AddrMode.Acc) {
regA = (regA-1) and 0xff
regP.Z = regA == 0
regP.N = (regA and 0b10000000) != 0
false
} else super.iDec()
}
override fun iInc() {
if (currentInstruction.mode == AddrMode.Acc) {
override fun iInc(): Boolean {
return if (currentInstruction.mode == AddrMode.Acc) {
regA = (regA+1) and 0xff
regP.Z = regA == 0
regP.N = (regA and 0b10000000) != 0
false
} else super.iInc()
}
private fun iBra() {
private fun iBra(): Boolean {
// unconditional branch
regPC = fetchedAddress
return false
}
private fun iTrb() {
private fun iTrb(): Boolean {
val data = getFetched()
regP.Z = data and regA == 0
write(fetchedAddress, data and regA.inv())
return false
}
private fun iTsb() {
private fun iTsb(): Boolean {
val data = getFetched()
regP.Z = data and regA == 0
write(fetchedAddress, data or regA)
return false
}
private fun iStz() {
private fun iStz(): Boolean {
write(fetchedAddress, 0)
return false
}
private fun iWai() {
private fun iWai(): Boolean {
waiting = Wait.Waiting
return false
}
private fun iStp() {
private fun iStp(): Boolean {
waiting = Wait.Stopped
return false
}
private fun iPhx() {
private fun iPhx(): Boolean {
pushStack(regX)
return false
}
private fun iPlx() {
private fun iPlx(): Boolean {
regX = popStack()
regP.Z = regX == 0
regP.N = (regX and 0b10000000) != 0
return false
}
private fun iPhy() {
private fun iPhy(): Boolean {
pushStack(regY)
return false
}
private fun iPly() {
private fun iPly(): Boolean {
regY = popStack()
regP.Z = regY == 0
regP.N = (regY and 0b10000000) != 0
return false
}
private fun iBbr0() {
private fun iBbr0(): Boolean {
val data = getFetched()
if (data and 1 == 0) regPC = fetchedAddressZpr
if (data and 1 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iBbr1() {
private fun iBbr1(): Boolean {
val data = getFetched()
if (data and 2 == 0) regPC = fetchedAddressZpr
if (data and 2 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iBbr2() {
private fun iBbr2(): Boolean {
val data = getFetched()
if (data and 4 == 0) regPC = fetchedAddressZpr
if (data and 4 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iBbr3() {
private fun iBbr3(): Boolean {
val data = getFetched()
if (data and 8 == 0) regPC = fetchedAddressZpr
if (data and 8 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iBbr4() {
private fun iBbr4(): Boolean {
val data = getFetched()
if (data and 16 == 0) regPC = fetchedAddressZpr
if (data and 16 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iBbr5() {
private fun iBbr5(): Boolean {
val data = getFetched()
if (data and 32 == 0) regPC = fetchedAddressZpr
if (data and 32 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iBbr6() {
private fun iBbr6(): Boolean {
val data = getFetched()
if (data and 64 == 0) regPC = fetchedAddressZpr
if (data and 64 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iBbr7() {
private fun iBbr7(): Boolean {
val data = getFetched()
if (data and 128 == 0) regPC = fetchedAddressZpr
if (data and 128 == 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iBbs0() {
private fun iBbs0(): Boolean {
val data = getFetched()
if (data and 1 != 0) regPC = fetchedAddressZpr
if (data and 1 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iBbs1() {
private fun iBbs1(): Boolean {
val data = getFetched()
if (data and 2 != 0) regPC = fetchedAddressZpr
if (data and 2 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iBbs2() {
private fun iBbs2(): Boolean {
val data = getFetched()
if (data and 4 != 0) regPC = fetchedAddressZpr
if (data and 4 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iBbs3() {
private fun iBbs3(): Boolean {
val data = getFetched()
if (data and 8 != 0) regPC = fetchedAddressZpr
if (data and 8 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iBbs4() {
private fun iBbs4(): Boolean {
val data = getFetched()
if (data and 16 != 0) regPC = fetchedAddressZpr
if (data and 16 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iBbs5() {
private fun iBbs5(): Boolean {
val data = getFetched()
if (data and 32 != 0) regPC = fetchedAddressZpr
if (data and 32 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iBbs6() {
private fun iBbs6(): Boolean {
val data = getFetched()
if (data and 64 != 0) regPC = fetchedAddressZpr
if (data and 64 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iBbs7() {
private fun iBbs7(): Boolean {
val data = getFetched()
if (data and 128 != 0) regPC = fetchedAddressZpr
if (data and 128 != 0) {
regPC = fetchedAddressZpr
instrCycles++
}
return false
}
private fun iSmb0() {
private fun iSmb0(): Boolean {
val data = getFetched()
write(fetchedAddress, data or 1)
return false
}
private fun iSmb1() {
private fun iSmb1(): Boolean {
val data = getFetched()
write(fetchedAddress, data or 2)
return false
}
private fun iSmb2() {
private fun iSmb2(): Boolean {
val data = getFetched()
write(fetchedAddress, data or 4)
return false
}
private fun iSmb3() {
private fun iSmb3(): Boolean {
val data = getFetched()
write(fetchedAddress, data or 8)
return false
}
private fun iSmb4() {
private fun iSmb4(): Boolean {
val data = getFetched()
write(fetchedAddress, data or 16)
return false
}
private fun iSmb5() {
private fun iSmb5(): Boolean {
val data = getFetched()
write(fetchedAddress, data or 32)
return false
}
private fun iSmb6() {
private fun iSmb6(): Boolean {
val data = getFetched()
write(fetchedAddress, data or 64)
return false
}
private fun iSmb7() {
private fun iSmb7(): Boolean {
val data = getFetched()
write(fetchedAddress, data or 128)
return false
}
private fun iRmb0() {
private fun iRmb0(): Boolean {
val data = getFetched()
write(fetchedAddress, data and 0b11111110)
return false
}
private fun iRmb1() {
private fun iRmb1(): Boolean {
val data = getFetched()
write(fetchedAddress, data and 0b11111101)
return false
}
private fun iRmb2() {
private fun iRmb2(): Boolean {
val data = getFetched()
write(fetchedAddress, data and 0b11111011)
return false
}
private fun iRmb3() {
private fun iRmb3(): Boolean {
val data = getFetched()
write(fetchedAddress, data and 0b11110111)
return false
}
private fun iRmb4() {
private fun iRmb4(): Boolean {
val data = getFetched()
write(fetchedAddress, data and 0b11101111)
return false
}
private fun iRmb5() {
private fun iRmb5(): Boolean {
val data = getFetched()
write(fetchedAddress, data and 0b11011111)
return false
}
private fun iRmb6() {
private fun iRmb6(): Boolean {
val data = getFetched()
write(fetchedAddress, data and 0b10111111)
return false
}
private fun iRmb7() {
private fun iRmb7(): Boolean {
val data = getFetched()
write(fetchedAddress, data and 0b01111111)
return false
}
}

View File

@ -0,0 +1,110 @@
package razorvine.ksim65
import razorvine.ksim65.components.Address
import razorvine.ksim65.components.UByte
class Disassembler(cpu: Cpu6502) {
private val instructions = cpu.instructions
fun disassemble(memory: Array<UByte>, range: IntRange, baseAddress: Address): Pair<List<String>, Address> {
var offset = range.first
val result = mutableListOf<String>()
while (offset <= range.last) {
val dis = disassembleOneInstruction(memory, offset, baseAddress)
result.add(dis.first)
offset += dis.second
}
return Pair(result, offset+baseAddress)
}
fun disassembleOneInstruction(memory: Array<UByte>, offset: Int, baseAddress: Address): Pair<String, Int> {
val spacing1 = " "
val spacing2 = " "
val spacing3 = " "
val byte = memory[offset]
val line = "\$${hexW(offset+baseAddress)} ${hexB(byte)} "
val opcode = instructions[byte.toInt()]
return when (opcode.mode) {
Cpu6502.AddrMode.Acc -> {
Pair(line+"$spacing1 ${opcode.mnemonic} a", 1)
}
Cpu6502.AddrMode.Imp -> {
Pair(line+"$spacing1 ${opcode.mnemonic}", 1)
}
Cpu6502.AddrMode.Imm -> {
val value = memory[offset+1]
Pair(line+"${hexB(value)} $spacing2 ${opcode.mnemonic} #\$${hexB(value)}", 2)
}
Cpu6502.AddrMode.Zp -> {
val zpAddr = memory[offset+1]
Pair(line+"${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)}", 2)
}
Cpu6502.AddrMode.Zpr -> {
// addressing mode used by the 65C02, put here for convenience rather than the subclass
val zpAddr = memory[offset+1]
val rel = memory[offset+2]
val target = (if (rel <= 0x7f) offset+3+rel+baseAddress else offset+3-(256-rel)+baseAddress) and 0xffff
Pair(line+"${hexB(zpAddr)} ${hexB(rel)} $spacing3 ${opcode.mnemonic} \$${hexB(zpAddr)}, \$${hexW(target, true)}", 3)
}
Cpu6502.AddrMode.Izp -> {
// addressing mode used by the 65C02, put here for convenience rather than the subclass
val zpAddr = memory[offset+1]
Pair(line+"${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$(${hexB(zpAddr)})", 2)
}
Cpu6502.AddrMode.IaX -> {
// addressing mode used by the 65C02, put here for convenience rather than the subclass
val lo = memory[offset+1]
val hi = memory[offset+2]
val absAddr = lo.toInt() or (hi.toInt() shl 8)
Pair(line+"${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$(${hexW(absAddr)},x)", 3)
}
Cpu6502.AddrMode.ZpX -> {
val zpAddr = memory[offset+1]
Pair(line+"${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},x", 2)
}
Cpu6502.AddrMode.ZpY -> {
val zpAddr = memory[offset+1]
Pair(line+"${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},y", 2)
}
Cpu6502.AddrMode.Rel -> {
val rel = memory[offset+1]
val target = (if (rel <= 0x7f) offset+2+rel+baseAddress else offset+2-(256-rel)+baseAddress) and 0xffff
Pair(line+"${hexB(rel)} $spacing2 ${opcode.mnemonic} \$${hexW(target, true)}", 2)
}
Cpu6502.AddrMode.Abs -> {
val lo = memory[offset+1]
val hi = memory[offset+2]
val absAddr = lo.toInt() or (hi.toInt() shl 8)
Pair(line+"${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)}", 3)
}
Cpu6502.AddrMode.AbsX -> {
val lo = memory[offset+1]
val hi = memory[offset+2]
val absAddr = lo.toInt() or (hi.toInt() shl 8)
Pair(line+"${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)},x", 3)
}
Cpu6502.AddrMode.AbsY -> {
val lo = memory[offset+1]
val hi = memory[offset+2]
val absAddr = lo.toInt() or (hi.toInt() shl 8)
Pair(line+"${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)},y", 3)
}
Cpu6502.AddrMode.Ind -> {
val lo = memory[offset+1]
val hi = memory[offset+2]
val indirectAddr = lo.toInt() or (hi.toInt() shl 8)
Pair(line+"${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} (\$${hexW(indirectAddr)})", 3)
}
Cpu6502.AddrMode.IzX -> {
val zpAddr = memory[offset+1]
Pair(line+"${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)},x)", 2)
}
Cpu6502.AddrMode.IzY -> {
val zpAddr = memory[offset+1]
Pair(line+"${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)}),y", 2)
}
}
}
}

View File

@ -7,6 +7,7 @@ import java.io.File
interface IVirtualMachine {
fun step()
fun pause(paused: Boolean)
fun reset()
fun getZeroAndStackPages(): Array<UByte>
fun loadFileInRam(file: File, loadAddress: Address?)

View File

@ -1,14 +1,10 @@
package razorvine.ksim65
import kotlin.math.max
class Monitor(val bus: Bus, val cpu: Cpu6502) {
private val instructions by lazy {
val instr = cpu.instructions.withIndex().associate {
Pair(it.value.mnemonic, it.value.mode) to it.index
}.toMutableMap()
instr[Pair("nop", Cpu6502.AddrMode.Imp)] = 0xea
instr.toMap()
}
private val disassembler = Disassembler(cpu)
fun command(command: String): IVirtualMachine.MonitorCmdResult {
if (command.isEmpty()) return IVirtualMachine.MonitorCmdResult("", "", false)
@ -22,9 +18,9 @@ class Monitor(val bus: Bus, val cpu: Cpu6502) {
val parts = command.substring(1).trim().split(' ')
if (parts.size != 3) IVirtualMachine.MonitorCmdResult("?syntax error", command, false)
else {
val start = parseNumber(parts[0])
val end = parseNumber(parts[1])
val value = parseNumber(parts[2]).toShort()
val start = Assembler.parseNumber(parts[0])
val end = Assembler.parseNumber(parts[1])
val value = Assembler.parseNumber(parts[2]).toShort()
for (addr in start..end) {
bus.write(addr, value)
}
@ -33,12 +29,12 @@ class Monitor(val bus: Bus, val cpu: Cpu6502) {
}
'm' -> {
val addresses = command.substring(1).trim().split(' ')
val start = parseNumber(addresses[0])
val end = if (addresses.size > 1) parseNumber(addresses[1]) else start+1
val start = Assembler.parseNumber(addresses[0])
val end = if (addresses.size > 1) Assembler.parseNumber(addresses[1]) else start+1
val result = mutableListOf<String>()
for (addr in start until end step 16) {
result.add("m$${hexW(addr)} "+(0..15).joinToString(" ") { hexB(bus.read(addr+it)) }+" "+(0..15).joinToString("") {
val chr = bus.read(addr+it).toChar()
val chr = bus.read(addr+it).toInt().toChar()
if (chr.isLetterOrDigit()) chr.toString()
else "."
})
@ -47,19 +43,19 @@ class Monitor(val bus: Bus, val cpu: Cpu6502) {
}
'p' -> {
val numbers = command.substring(1).trim().split(' ')
val address = parseNumber(numbers[0])
val values = numbers.drop(1).map { parseNumber(it) }
val address = Assembler.parseNumber(numbers[0])
val values = numbers.drop(1).map { Assembler.parseNumber(it) }
values.forEachIndexed { index, i -> bus.write(address+index, i.toShort()) }
IVirtualMachine.MonitorCmdResult("ok", "", true)
}
'i' -> {
val addresses = command.substring(1).trim().split(' ')
val start = parseNumber(addresses[0])
val end = if (addresses.size > 1) parseNumber(addresses[1]) else start+1
val start = Assembler.parseNumber(addresses[0])
val end = if (addresses.size > 1) Assembler.parseNumber(addresses[1]) else start+1
val result = mutableListOf<String>()
for (addr in start until end step 64) {
result.add("i$${hexW(addr)} "+(0..63).joinToString("") {
val chr = bus.read(addr+it).toChar()
val chr = bus.read(addr+it).toInt().toChar()
if (chr.isLetterOrDigit()) chr.toString()
else "."
})
@ -67,34 +63,44 @@ class Monitor(val bus: Bus, val cpu: Cpu6502) {
IVirtualMachine.MonitorCmdResult(result.joinToString("\n"), "", true)
}
'$' -> {
val number = parseNumber(command)
val number = Assembler.parseNumber(command)
val output = "$${hexW(number)} #$number %${number.toString(2)}"
IVirtualMachine.MonitorCmdResult(output, "", true)
}
'#' -> {
val number = parseNumber(command)
val number = Assembler.parseNumber(command)
val output = "$${hexW(number)} #$number %${number.toString(2)}"
IVirtualMachine.MonitorCmdResult(output, "", true)
}
'%' -> {
val number = parseNumber(command)
val number = Assembler.parseNumber(command)
val output = "$${hexW(number)} #$number %${number.toString(2)}"
IVirtualMachine.MonitorCmdResult(output, "", true)
}
'g' -> {
val address = parseNumber(command.substring(1))
val address = Assembler.parseNumber(command.substring(1))
cpu.regPC = address
IVirtualMachine.MonitorCmdResult("", "", true)
}
'a' -> {
val parts = command.substring(1).trim().split(' ')
assemble(command, parts)
val address = if(parts.size>=2) Assembler.parseNumber(parts[0]) else 0
val assembler = Assembler(cpu, bus.memoryComponentFor(address), address)
val result = assembler.assemble(command.substring(1).trimStart())
if(result.success) {
val memory = (result.startAddress..result.startAddress+result.numBytes).map { bus[it] }.toTypedArray()
val d = disassembler.disassembleOneInstruction(memory, 0, result.startAddress)
IVirtualMachine.MonitorCmdResult(d.first, "a$${hexW(result.startAddress+result.numBytes)} ", false)
}
else
IVirtualMachine.MonitorCmdResult(result.error, command, false)
}
'd' -> {
val addresses = command.substring(1).trim().split(' ')
val start = parseNumber(addresses[0])
val end = if (addresses.size > 1) parseNumber(addresses[1]) else start
val disassem = cpu.disassemble(bus.memoryComponentFor(start), start, end)
val start = Assembler.parseNumber(addresses[0])
val end = if (addresses.size > 1) Assembler.parseNumber(addresses[1]) else start
val memory = (start .. max(0xffff, end+3)).map {bus[it]}.toTypedArray()
val disassem = disassembler.disassemble(memory, 0 .. end-start, start)
IVirtualMachine.MonitorCmdResult(disassem.first.joinToString("\n") { "d$it" }, "d$${hexW(disassem.second)}", false)
}
else -> {
@ -102,153 +108,4 @@ class Monitor(val bus: Bus, val cpu: Cpu6502) {
}
}
}
private fun assemble(command: String, parts: List<String>): IVirtualMachine.MonitorCmdResult {
if (parts.size < 2) return IVirtualMachine.MonitorCmdResult("done", "", false)
val address = parseNumber(parts[0])
val mnemonic = parts[1].toLowerCase()
when (parts.size) {
2 -> {
// implied or acc
var instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Imp)]
if (instruction == null) instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Acc)]
if (instruction == null) return IVirtualMachine.MonitorCmdResult("?invalid instruction", command, false)
bus.write(address, instruction.toShort())
}
3 -> {
val arg = parts[2]
when {
arg.startsWith('#') -> {
// immediate
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Imm)] ?: return IVirtualMachine.MonitorCmdResult("?invalid instruction", command, false)
bus.write(address, instruction.toShort())
bus.write(address+1, parseNumber(arg.substring(1), true).toShort())
}
arg.startsWith("(") && arg.endsWith(",x)") -> {
// indirect X
val indAddress = try {
parseNumber(arg.substring(1, arg.length-3))
} catch (x: NumberFormatException) {
return IVirtualMachine.MonitorCmdResult("?invalid instruction", command, false)
}
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.IzX)] ?: return IVirtualMachine.MonitorCmdResult("?invalid instruction", command, false)
bus.write(address, instruction.toShort())
bus.write(address+1, indAddress.toShort())
}
arg.startsWith("(") && arg.endsWith("),y") -> {
// indirect Y
val indAddress = try {
parseNumber(arg.substring(1, arg.length-3))
} catch (x: NumberFormatException) {
return IVirtualMachine.MonitorCmdResult("?invalid instruction", command, false)
}
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.IzY)] ?: return IVirtualMachine.MonitorCmdResult("?invalid instruction", command, false)
bus.write(address, instruction.toShort())
bus.write(address+1, indAddress.toShort())
}
arg.endsWith(",x") -> {
// indexed X or zpIndexed X
val indAddress = try {
parseNumber(arg.substring(1, arg.length-2))
} catch (x: NumberFormatException) {
return IVirtualMachine.MonitorCmdResult("?invalid instruction", command, false)
}
if (indAddress <= 255) {
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.ZpX)] ?: return IVirtualMachine.MonitorCmdResult(
"?invalid instruction", command, false)
bus.write(address, instruction.toShort())
bus.write(address+1, indAddress.toShort())
} else {
val instruction =
instructions[Pair(mnemonic, Cpu6502.AddrMode.AbsX)] ?: return IVirtualMachine.MonitorCmdResult("?invalid instruction", command, false)
bus.write(address, instruction.toShort())
bus.write(address+1, (indAddress and 255).toShort())
bus.write(address+2, (indAddress ushr 8).toShort())
}
}
arg.endsWith(",y") -> {
// indexed Y or zpIndexed Y
val indAddress = try {
parseNumber(arg.substring(1, arg.length-2))
} catch (x: NumberFormatException) {
return IVirtualMachine.MonitorCmdResult("?invalid instruction", command, false)
}
if (indAddress <= 255) {
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.ZpY)] ?: return IVirtualMachine.MonitorCmdResult(
"?invalid instruction", command, false)
bus.write(address, instruction.toShort())
bus.write(address+1, indAddress.toShort())
} else {
val instruction =
instructions[Pair(mnemonic, Cpu6502.AddrMode.AbsY)] ?: return IVirtualMachine.MonitorCmdResult("?invalid instruction", command, false)
bus.write(address, instruction.toShort())
bus.write(address+1, (indAddress and 255).toShort())
bus.write(address+2, (indAddress ushr 8).toShort())
}
}
arg.endsWith(")") -> {
// indirect (jmp)
val indAddress = try {
parseNumber(arg.substring(1, arg.length-1))
} catch (x: NumberFormatException) {
return IVirtualMachine.MonitorCmdResult("?invalid instruction", command, false)
}
val instruction = instructions[Pair(mnemonic, Cpu6502.AddrMode.Ind)] ?: return IVirtualMachine.MonitorCmdResult("?invalid instruction", command, false)
bus.write(address, instruction.toShort())
bus.write(address+1, (indAddress and 255).toShort())
bus.write(address+2, (indAddress ushr 8).toShort())
}
else -> {
val instr = instructions[Pair(mnemonic, Cpu6502.AddrMode.Rel)]
if (instr != null) {
// relative address
val rel = try {
parseNumber(arg)
} catch (x: NumberFormatException) {
return IVirtualMachine.MonitorCmdResult("?invalid instruction", command, false)
}
bus.write(address, instr.toShort())
bus.write(address+1, (rel-address-2 and 255).toShort())
} else {
// absolute or absZp
val absAddress = try {
parseNumber(arg)
} catch (x: NumberFormatException) {
return IVirtualMachine.MonitorCmdResult("?invalid instruction", command, false)
}
if (absAddress <= 255) {
val absInstr = instructions[Pair(mnemonic, Cpu6502.AddrMode.Zp)] ?: return IVirtualMachine.MonitorCmdResult(
"?invalid instruction", command, false)
bus.write(address, absInstr.toShort())
bus.write(address+1, absAddress.toShort())
} else {
val absInstr =
instructions[Pair(mnemonic, Cpu6502.AddrMode.Abs)] ?: return IVirtualMachine.MonitorCmdResult("?invalid instruction", command, false)
bus.write(address, absInstr.toShort())
bus.write(address+1, (absAddress and 255).toShort())
bus.write(address+2, (absAddress ushr 8).toShort())
}
}
}
}
}
else -> return IVirtualMachine.MonitorCmdResult("?syntax error", command, false)
}
val disassem = cpu.disassemble(bus.memoryComponentFor(address), address, address)
return IVirtualMachine.MonitorCmdResult(disassem.first.single(), "a$${hexW(disassem.second)} ", false)
}
private fun parseNumber(number: String, decimalFirst: Boolean = false): Int {
val num = number.trim()
if (num.isBlank()) return 0
if (decimalFirst && num[0].isDigit()) return num.toInt(10)
return when (num[0]) {
'$' -> num.substring(1).trimStart().toInt(16)
'#' -> num.substring(1).trimStart().toInt(10)
'%' -> num.substring(1).trimStart().toInt(2)
else -> num.toInt(16)
}
}
}

View File

@ -2,20 +2,16 @@ package razorvine.ksim65
import razorvine.ksim65.components.Address
fun hexW(number: Address, allowSingleByte: Boolean = false): String {
val msb = number ushr 8
val lsb = number and 0xff
return if (msb == 0 && allowSingleByte) hexB(lsb)
else hexB(msb)+hexB(lsb)
}
fun hexW(number: Int, allowSingleByte: Boolean = false) =
if(allowSingleByte && (number and 0xff00 == 0)) {
number.toString(16).padStart(2, '0')
} else {
number.toString(16).padStart(4, '0')
}
fun hexB(number: Short): String = hexB(number.toInt())
fun hexB(number: Int): String {
val hexdigits = "0123456789abcdef"
val loNibble = number and 15
val hiNibble = number ushr 4
return hexdigits[hiNibble].toString()+hexdigits[loNibble]
}
fun hexB(number: Int) = number.toString(16).padStart(2, '0')
fun hexB(number: Short) = hexB(number.toInt())
typealias BreakpointHandler = (cpu: Cpu6502, pc: Address) -> Cpu6502.BreakpointResultAction

View File

@ -28,8 +28,8 @@ abstract class BusComponent {
* Most I/O components fall into this category.
*/
abstract class MemMappedComponent(val startAddress: Address, val endAddress: Address) : BusComponent() {
abstract operator fun get(address: Address): UByte
abstract operator fun set(address: Address, data: UByte)
abstract operator fun get(offset: Int): UByte
abstract operator fun set(offset: Int, data: UByte)
init {
require(endAddress >= startAddress)
@ -39,13 +39,13 @@ abstract class MemMappedComponent(val startAddress: Address, val endAddress: Add
fun hexDump(from: Address, to: Address, charmapper: ((Short) -> Char)? = null) {
(from..to).chunked(16).forEach {
print("\$${it.first().toString(16).padStart(4, '0')} ")
val bytes = it.map { address -> get(address) }
val bytes = it.map { address -> get(address - startAddress) }
bytes.forEach { byte ->
print(byte.toString(16).padStart(2, '0')+" ")
}
print(" ")
val chars = if (charmapper != null) bytes.map { b -> charmapper(b) }
else bytes.map { b -> if (b in 32..255) b.toChar() else '.' }
else bytes.map { b -> if (b in 32..255) b.toInt().toChar() else '.' }
println(chars.joinToString(""))
}
}

View File

@ -52,7 +52,7 @@ class Display(startAddress: Address, endAddress: Address, private val host: IHos
}
override fun reset() {
charMatrix.forEach { it.fill(' '.toShort()) }
charMatrix.forEach { it.fill(' '.code.toShort()) }
cursorX = 0
cursorY = 0
charposX = 0
@ -62,8 +62,8 @@ class Display(startAddress: Address, endAddress: Address, private val host: IHos
host.clearScreen()
}
override operator fun get(address: Address): UByte {
return when (address-startAddress) {
override operator fun get(offset: Int): UByte {
return when (offset) {
0x00 -> charposX.toShort()
0x01 -> charposY.toShort()
0x02 -> {
@ -87,14 +87,14 @@ class Display(startAddress: Address, endAddress: Address, private val host: IHos
}
}
override operator fun set(address: Address, data: UByte) {
when (address-startAddress) {
override operator fun set(offset: Int, data: UByte) {
when (offset) {
0x00 -> charposX = data.toInt()
0x01 -> charposY = data.toInt()
0x02 -> {
if (charposY in 0 until charHeight && charposX in 0 until charWidth) {
charMatrix[charposY][charposX] = data
host.setChar(charposX, charposY, data.toChar())
host.setChar(charposX, charposY, data.toInt().toChar())
}
}
0x03 -> pixelX = (pixelX and 0xff00) or data.toInt()
@ -102,7 +102,7 @@ class Display(startAddress: Address, endAddress: Address, private val host: IHos
0x05 -> pixelY = (pixelY and 0xff00) or data.toInt()
0x06 -> pixelY = (pixelY and 0x00ff) or (data.toInt() shl 8)
0x07 -> {
if (pixelX in 0 until ScreenDefs.SCREEN_WIDTH && pixelY in 0 until ScreenDefs.SCREEN_HEIGHT) {
if (pixelX in 0 until ScreenDefs.COLUMNS*charWidth && pixelY in 0 until ScreenDefs.ROWS*charHeight) {
if (data == 0.toShort()) host.clearPixel(pixelX, pixelY)
else host.setPixel(pixelX, pixelY)
}
@ -121,7 +121,7 @@ class Display(startAddress: Address, endAddress: Address, private val host: IHos
cursorX = charWidth-1
}
}
charMatrix[cursorY][cursorX] = ' '.toShort()
charMatrix[cursorY][cursorX] = ' '.code.toShort()
host.setChar(cursorX, cursorY, ' ')
}
0x09 -> {
@ -142,7 +142,7 @@ class Display(startAddress: Address, endAddress: Address, private val host: IHos
else -> {
// set character on screen
charMatrix[cursorY][cursorX] = data
host.setChar(cursorX, cursorY, data.toChar())
host.setChar(cursorX, cursorY, data.toInt().toChar())
cursorX++
if (cursorX >= charWidth) {
cursorX = 0
@ -164,7 +164,7 @@ class Display(startAddress: Address, endAddress: Address, private val host: IHos
charMatrix[y+1].copyInto(charMatrix[y])
}
for (x in 0 until charWidth) {
charMatrix[charHeight-1][x] = ' '.toShort()
charMatrix[charHeight-1][x] = ' '.code.toShort()
}
cursorY--
host.scrollUp()

View File

@ -23,13 +23,12 @@ class Keyboard(startAddress: Address, endAddress: Address, private val host: IHo
override fun clock() {}
override fun reset() {}
override operator fun get(address: Address): UByte {
return when (address-startAddress) {
0x00 -> host.keyboard()?.toShort() ?: 0
override operator fun get(offset: Int): UByte {
return when (offset) {
0x00 -> host.keyboard()?.code?.toShort() ?: 0
else -> 0xff
}
}
override operator fun set(address: Address, data: UByte) { /* read-only device */
}
override operator fun set(offset: Int, data: UByte) { /* read-only device */ }
}

View File

@ -25,8 +25,8 @@ class Mouse(startAddress: Address, endAddress: Address, private val host: IHostI
private var mouse = host.mouse()
override operator fun get(address: Address): UByte {
return when (address-startAddress) {
override operator fun get(offset: Int): UByte {
return when (offset) {
0x00 -> (mouse.x and 0xff).toShort()
0x01 -> (mouse.x ushr 8).toShort()
0x02 -> (mouse.y and 0xff).toShort()
@ -41,7 +41,7 @@ class Mouse(startAddress: Address, endAddress: Address, private val host: IHostI
}
}
override operator fun set(address: Address, data: UByte) {
if (address-startAddress == 0x05) mouse = host.mouse()
override operator fun set(offset: Int, data: UByte) {
if (offset == 0x05) mouse = host.mouse()
}
}

View File

@ -18,16 +18,16 @@ class ParallelPort(startAddress: Address, endAddress: Address) : MemMappedCompon
override fun clock() {}
override fun reset() {}
override operator fun get(address: Address): UByte {
return if (address == startAddress) dataByte
override operator fun get(offset: Int): UByte {
return if (offset == 0) dataByte
else 0xff
}
override operator fun set(address: Address, data: UByte) {
if (address == startAddress) dataByte = data
else if (address == endAddress) {
override operator fun set(offset: Int, data: UByte) {
if (offset == 0) dataByte = data
else if (offset == 1) {
if ((data.toInt() and 1) == 1) {
val char = dataByte.toChar()
val char = dataByte.toInt().toChar()
println("PARALLEL WRITE: '$char'")
}
}

View File

@ -10,10 +10,10 @@ import java.io.InputStream
class Ram(startAddress: Address, endAddress: Address) : MemoryComponent(startAddress, endAddress) {
override val data = Array<UByte>(endAddress-startAddress+1) { 0 }
override operator fun get(address: Address): UByte = data[address-startAddress]
override operator fun get(offset: Int): UByte = data[offset]
override operator fun set(address: Address, data: UByte) {
this.data[address-startAddress] = data
override operator fun set(offset: Int, data: UByte) {
this.data[offset] = data
}
override fun clock() {}

View File

@ -34,8 +34,8 @@ class RealTimeClock(startAddress: Address, endAddress: Address) : MemMappedCompo
/* never reset */
}
override operator fun get(address: Address): UByte {
return when (address-startAddress) {
override operator fun get(offset: Int): UByte {
return when (offset) {
0x00 -> {
val year = LocalDate.now().year
(year and 255).toShort()
@ -61,7 +61,5 @@ class RealTimeClock(startAddress: Address, endAddress: Address) : MemMappedCompo
}
}
override operator fun set(address: Address, data: UByte) {
/* real time clock can't be set */
}
override operator fun set(offset: Int, data: UByte) { /* real time clock can't be set */ }
}

View File

@ -6,15 +6,14 @@ import java.io.File
* A ROM chip (read-only memory).
*/
class Rom(startAddress: Address, endAddress: Address, initialData: Array<UByte>? = null) : MemoryComponent(startAddress, endAddress) {
override val data: Array<UByte> = initialData?.copyOf() ?: Array<UByte>(endAddress-startAddress+1) { 0 }
override val data: Array<UByte> = initialData?.copyOf() ?: Array(endAddress-startAddress+1) { 0 }
init {
require(endAddress-startAddress+1 == data.size) { "rom address range doesn't match size of data bytes" }
}
override operator fun get(address: Address): UByte = data[address-startAddress]
override operator fun set(address: Address, data: UByte) { /* read-only */
}
override operator fun get(offset: Int): UByte = data[offset]
override operator fun set(offset: Int, data: UByte) { /* read-only */ }
override fun clock() {}
override fun reset() {}
@ -27,12 +26,7 @@ class Rom(startAddress: Address, endAddress: Address, initialData: Array<UByte>?
load(bytes)
}
fun load(data: Array<UByte>) = data.forEachIndexed { index, byte ->
this.data[index] = byte
}
fun load(data: Array<UByte>) = data.copyInto(this.data)
fun load(data: ByteArray) = data.forEachIndexed { index, byte ->
this.data[index] = if (byte >= 0) byte.toShort()
else (256+byte).toShort()
}
fun load(data: ByteArray) = data.map { (it.toInt() and 255).toShort() }.toTypedArray().copyInto(this.data)
}

View File

@ -33,8 +33,8 @@ class Timer(startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemM
if (enabled && interval > 0) {
counter++
if (counter == interval) {
if (nmi) cpu.nmi()
else cpu.irq()
if (nmi) cpu.nmiAsserted = true
else cpu.irqAsserted = true
counter = 0
}
}
@ -47,8 +47,8 @@ class Timer(startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemM
nmi = false
}
override operator fun get(address: Address): UByte {
return when (address-startAddress) {
override operator fun get(offset: Int): UByte {
return when (offset) {
0x00 -> {
var data = 0
if (enabled) data = data or 0b00000001
@ -62,8 +62,8 @@ class Timer(startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemM
}
}
override operator fun set(address: Address, data: UByte) {
when (address-startAddress) {
override operator fun set(offset: Int, data: UByte) {
when (offset) {
0x00 -> {
val i = data.toInt()
enabled = (i and 0b00000001) != 0

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,24 @@
Copyright (c) 2018-2020, Frederic Cambus
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1 +1 @@
version=1.5
version=1.10

View File

@ -10,6 +10,7 @@
SCREEN_WIDTH=640
* = $1000
irq_timer_cycles = 10000 ; every time this number of cycles passed, an IRQ occurs
start
sei
@ -20,11 +21,11 @@ start
sta IRQVEC
lda #>irq
sta IRQVEC+1
lda #<2000
sta TIMER+1 ; every 2000 clock cycles an irq
lda #>2000
lda #<irq_timer_cycles
sta TIMER+1
lda #>irq_timer_cycles
sta TIMER+2
lda #0
lda #irq_timer_cycles >> 16
sta TIMER+3
lda #1
sta TIMER+0
@ -40,7 +41,7 @@ start
jsr print
jmp +
_title1 .text "**** COMMODORE 64 BASIC V2 ****", 10, 10, " 64K RAM SYSTEM 38911 BASIC BYTES FREE", 10, 10, "READY.",10,0
_title1 .text "**** COMMODORE 64 BASIC V9 ****", 10, 10, " 64K RAM SYSTEM 98765 BASIC BYTES FREE", 10, 10, "READY.",10,0
_text2 .text 10,"Nah, only joking, this is not a weird C-64.",10,"This is a working fantasy 8-bit 6502 machine though!",10
.text "Type some stuff on the keyboard, use the mouse (with Left button/Right button)", 10, "to draw/erase pixels.",10,10,0
_text3 .text "Mouse drawing and keyboard scanning: done in main program loop.",10
@ -92,6 +93,7 @@ irq
pha
tya
pha
; we don't check for BRK flag because we're lazy
lda DISPLAY+0
pha
@ -104,6 +106,7 @@ irq
lda #<_time_msg
ldy #>_time_msg
jsr textout
; read the clock now
; YEAR
lda RTC+0
@ -112,6 +115,7 @@ irq
lda #<DecTenThousands
ldy #>DecTenThousands
jsr textout
lda #'-'
sta DISPLAY+2
inc DISPLAY+0
@ -130,6 +134,7 @@ irq
lda #<DecTens
ldy #>DecTens
jsr textout
lda #'/'
sta DISPLAY+2
inc DISPLAY+0
@ -157,6 +162,7 @@ irq
lda #<DecTens
ldy #>DecTens
jsr textout
lda #'.'
sta DISPLAY+2
inc DISPLAY+0
@ -184,7 +190,7 @@ _time_msg .text "The current date and time is: ",0
; ----- routines
delay ldx #50
delay ldx #100
- ldy #0
- nop
dey

Binary file not shown.

View File

@ -34,7 +34,8 @@ chk_z = 0 ; check zero flag
chk_c = 1 ; check carry flag
end_of_test macro
db $db ;execute 65C02 stop instruction
brk
; db $db ;execute 65C02 stop instruction
endm
bss
@ -117,14 +118,14 @@ NEXT2 inc N2 ; [6] see text
bpl LOOP1 ; loop through both values of the carry flag
lda #0 ; test passed, so store 0 in ERROR
sta ERROR
DONE
DONE
end_of_test
; Calculate the actual decimal mode accumulator and flags, the accumulator
; and flag results when N1 is added to N2 using binary arithmetic, the
; predicted accumulator result, the predicted carry flag, and the predicted
; V flag
;
; V flag
;
ADD sed ; decimal mode
cpy #1 ; set carry if Y = 1, clear carry if Y = 0
lda N1
@ -138,7 +139,7 @@ ADD sed ; decimal mode
lda N1
adc N2
sta HA ; accumulator result of N1+N2 using binary arithmetic
php
pla
sta HNVZC ; flags result of N1+N2 using binary arithmetic
@ -153,10 +154,10 @@ ADD sed ; decimal mode
and #$0F
sec
A1 ora N1H
;
;
; if N1L + N2L < $0A, then add N2 & $F0
; if N1L + N2L >= $0A, then add (N2 & $F0) + $0F + 1 (carry is set)
;
;
adc N2H,x
php
bcs A2
@ -169,16 +170,16 @@ A3 sta AR ; predicted accumulator result
pla
sta CF ; predicted carry result
pla
;
;
; note that all 8 bits of the P register are stored in VF
;
;
sta VF ; predicted V flags
rts
; Calculate the actual decimal mode accumulator and flags, and the
; accumulator and flag results when N2 is subtracted from N1 using binary
; arithmetic
;
;
SUB sed ; decimal mode
cpy #1 ; set carry if Y = 1, clear carry if Y = 0
lda N1
@ -192,15 +193,15 @@ SUB sed ; decimal mode
lda N1
sbc N2
sta HA ; accumulator result of N1-N2 using binary arithmetic
php
pla
sta HNVZC ; flags result of N1-N2 using binary arithmetic
rts
if cputype != 1
; Calculate the predicted SBC accumulator result for the 6502 and 65816
;
;
SUB1 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
lda N1L
sbc N2L
@ -211,17 +212,17 @@ SUB1 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
and #$0F
clc
S11 ora N1H
;
;
; if N1L - N2L >= 0, then subtract N2 & $F0
; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear)
;
;
sbc N2H,x
bcs S12
sbc #$5F ; subtract $60 (carry is clear)
S12 sta AR
rts
endif
if cputype = 1
; Calculate the predicted SBC accumulator result for the 6502 and 65C02
;
@ -234,10 +235,10 @@ SUB2 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
and #$0F
clc
S21 ora N1H
;
;
; if N1L - N2L >= 0, then subtract N2 & $F0
; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear)
;
;
sbc N2H,x
bcs S22
sbc #$5F ; subtract $60 (carry is clear)
@ -247,14 +248,14 @@ S22 cpx #0
S23 sta AR ; predicted accumulator result
rts
endif
; Compare accumulator actual results to predicted results
;
; Return:
;
; Return:
; Z flag = 1 (BEQ branch) if same
; Z flag = 0 (BNE branch) if different
;
COMPARE
;
COMPARE
if chk_a = 1
lda DA
cmp AR
@ -284,22 +285,22 @@ COMPARE
and #1 ; mask off C flag
endif
C1 rts
; These routines store the predicted values for ADC and SBC for the 6502,
; 65C02, and 65816 in AR, CF, NF, VF, and ZF
if cputype = 0
A6502 lda VF ; 6502
;
;
; since all 8 bits of the P register were stored in VF, bit 7 of VF contains
; the N flag for NF
;
;
sta NF
lda HNVZC
sta ZF
rts
S6502 jsr SUB1
lda HNVZC
sta NF
@ -317,7 +318,7 @@ A6502 lda AR ; 65C02
sta NF
sta ZF
rts
S6502 jsr SUB2
lda AR
php
@ -330,7 +331,7 @@ S6502 jsr SUB2
rts
endif
if cputype = 2
if cputype = 2
A6502 lda AR ; 65C816
php
@ -338,7 +339,7 @@ A6502 lda AR ; 65C816
sta NF
sta ZF
rts
S6502 jsr SUB1
lda AR
php

View File

@ -1,7 +1,7 @@
;
; 6 5 0 2 F U N C T I O N A L T E S T
;
; Copyright (C) 2012-2015 Klaus Dormann
; Copyright (C) 2012-2020 Klaus Dormann
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
@ -21,10 +21,11 @@
; addressing modes with focus on propper setting of the processor status
; register bits.
;
; version 04-dec-2017
; version 05-jan-2020
; contact info at http://2m5.de or email K@2m5.de
;
; assembled with AS65 from http://www.kingswood-consulting.co.uk/assemblers/
; assembled with AS65 written by Frank A. Kingswood
; The assembler as65_142.zip can be obtained from my GitHub repository
; command line switches: -l -m -s2 -w -h0
; | | | | no page headers in listing
; | | | wide listing (133 char/col)
@ -76,7 +77,8 @@
; 04-dec-2017 fixed BRK only tested with interrupts enabled
; added option to skip the remainder of a failing test
; in report.i65
; 05-jan-2020 fixed shifts not testing zero result and flag when last 1-bit
; is shifted out
; C O N F I G U R A T I O N
@ -96,17 +98,17 @@ load_data_direct = 1
I_flag = 3
;configure memory - try to stay away from memory used by the system
;zero_page memory start address, $50 (80) consecutive Bytes required
;zero_page memory start address, $52 (82) consecutive Bytes required
; add 2 if I_flag = 2
zero_page = $a
zero_page = $0
;data_segment memory start address, $6A (106) consecutive Bytes required
;data_segment memory start address, $7B (123) consecutive Bytes required
data_segment = $200
if (data_segment & $ff) != 0
ERROR ERROR ERROR low byte of data_segment MUST be $00 !!
endif
;code_segment memory start address, 13kB of consecutive space required
;code_segment memory start address, 13.1kB of consecutive space required
; add 2.5 kB if I_flag = 2
code_segment = $400
@ -621,7 +623,7 @@ irq_x ds 1 ;x register
flag_I_on ds 1 ;or mask to load flags
flag_I_off ds 1 ;and mask to load flags
endif
zpt ;5 bytes store/modify test area
zpt ;6 bytes store/modify test area
;add/subtract operand generation and result/flag prediction
adfc ds 1 ;carry flag before op
ad1 ds 1 ;operand 1 - accumulator
@ -631,6 +633,7 @@ adrh ds 1 ;expected result bit 8 (carry)
adrf ds 1 ;expected flags NV0000ZC (only binary mode)
sb2 ds 1 ;operand 2 complemented for subtract
zp_bss
zps db $80,1 ;additional shift pattern to test zero result & flag
zp1 db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
zp7f db $7f ;test pattern for compare
;logical zeropage operands
@ -672,10 +675,10 @@ zp_bss_end
test_case ds 1 ;current test number
ram_chksm ds 2 ;checksum for RAM integrity test
;add/subtract operand copy - abs tests write area
abst ;5 bytes store/modify test area
abst ;6 bytes store/modify test area
ada2 ds 1 ;operand 2
sba2 ds 1 ;operand 2 complemented for subtract
ds 3 ;fill remaining bytes
ds 4 ;fill remaining bytes
data_bss
if load_data_direct = 1
ex_andi and #0 ;execute immediate opcodes
@ -695,34 +698,35 @@ ex_orai ds 3
ex_adci ds 3
ex_sbci ds 3
endif
;zps db $80,1 ;additional shift patterns test zero result & flag
abs1 db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
abs7f db $7f ;test pattern for compare
;loads
fLDx db fn,fn,0,fz ;expected flags for load
fLDx db fn,fn,0,fz ;expected flags for load
;shifts
rASL ;expected result ASL & ROL -carry
rROL db $86,$04,$82,0 ; "
rROLc db $87,$05,$83,1 ;expected result ROL +carry
rLSR ;expected result LSR & ROR -carry
rROR db $61,$41,$20,0 ; "
rRORc db $e1,$c1,$a0,$80 ;expected result ROR +carry
fASL ;expected flags for shifts
fROL db fnc,fc,fn,fz ;no carry in
fROLc db fnc,fc,fn,0 ;carry in
fLSR
fROR db fc,0,fc,fz ;no carry in
fRORc db fnc,fn,fnc,fn ;carry in
rASL ;expected result ASL & ROL -carry
rROL db 0,2,$86,$04,$82,0
rROLc db 1,3,$87,$05,$83,1 ;expected result ROL +carry
rLSR ;expected result LSR & ROR -carry
rROR db $40,0,$61,$41,$20,0
rRORc db $c0,$80,$e1,$c1,$a0,$80 ;expected result ROR +carry
fASL ;expected flags for shifts
fROL db fzc,0,fnc,fc,fn,fz ;no carry in
fROLc db fc,0,fnc,fc,fn,0 ;carry in
fLSR
fROR db 0,fzc,fc,0,fc,fz ;no carry in
fRORc db fn,fnc,fnc,fn,fnc,fn ;carry in
;increments (decrements)
rINC db $7f,$80,$ff,0,1 ;expected result for INC/DEC
fINC db 0,fn,fn,fz,0 ;expected flags for INC/DEC
rINC db $7f,$80,$ff,0,1 ;expected result for INC/DEC
fINC db 0,fn,fn,fz,0 ;expected flags for INC/DEC
;logical memory operand
absOR db 0,$1f,$71,$80 ;test pattern for OR
absAN db $0f,$ff,$7f,$80 ;test pattern for AND
absEO db $ff,$0f,$8f,$8f ;test pattern for EOR
absOR db 0,$1f,$71,$80 ;test pattern for OR
absAN db $0f,$ff,$7f,$80 ;test pattern for AND
absEO db $ff,$0f,$8f,$8f ;test pattern for EOR
;logical accu operand
absORa db 0,$f1,$1f,0 ;test pattern for OR
absANa db $f0,$ff,$ff,$ff ;test pattern for AND
absEOa db $ff,$f0,$f0,$0f ;test pattern for EOR
absORa db 0,$f1,$1f,0 ;test pattern for OR
absANa db $f0,$ff,$ff,$ff ;test pattern for AND
absEOa db $ff,$f0,$f0,$0f ;test pattern for EOR
;logical results
absrlo db 0,$ff,$7f,$80
absflo db fz,fn,0,fn
@ -4070,91 +4074,91 @@ tstay6 lda abst,y
; testing shifts - ASL LSR ROL ROR all addressing modes
; shifts - accumulator
ldx #3
ldx #5
tasl
set_ax zp1,0
set_ax zps,0
asl a
tst_ax rASL,fASL,0
dex
bpl tasl
ldx #3
ldx #5
tasl1
set_ax zp1,$ff
set_ax zps,$ff
asl a
tst_ax rASL,fASL,$ff-fnzc
dex
bpl tasl1
ldx #3
ldx #5
tlsr
set_ax zp1,0
set_ax zps,0
lsr a
tst_ax rLSR,fLSR,0
dex
bpl tlsr
ldx #3
ldx #5
tlsr1
set_ax zp1,$ff
set_ax zps,$ff
lsr a
tst_ax rLSR,fLSR,$ff-fnzc
dex
bpl tlsr1
ldx #3
ldx #5
trol
set_ax zp1,0
set_ax zps,0
rol a
tst_ax rROL,fROL,0
dex
bpl trol
ldx #3
ldx #5
trol1
set_ax zp1,$ff-fc
set_ax zps,$ff-fc
rol a
tst_ax rROL,fROL,$ff-fnzc
dex
bpl trol1
ldx #3
ldx #5
trolc
set_ax zp1,fc
set_ax zps,fc
rol a
tst_ax rROLc,fROLc,0
dex
bpl trolc
ldx #3
ldx #5
trolc1
set_ax zp1,$ff
set_ax zps,$ff
rol a
tst_ax rROLc,fROLc,$ff-fnzc
dex
bpl trolc1
ldx #3
ldx #5
tror
set_ax zp1,0
set_ax zps,0
ror a
tst_ax rROR,fROR,0
dex
bpl tror
ldx #3
ldx #5
tror1
set_ax zp1,$ff-fc
set_ax zps,$ff-fc
ror a
tst_ax rROR,fROR,$ff-fnzc
dex
bpl tror1
ldx #3
ldx #5
trorc
set_ax zp1,fc
set_ax zps,fc
ror a
tst_ax rRORc,fRORc,0
dex
bpl trorc
ldx #3
ldx #5
trorc1
set_ax zp1,$ff
set_ax zps,$ff
ror a
tst_ax rRORc,fRORc,$ff-fnzc
dex
@ -4162,91 +4166,91 @@ trorc1
next_test
; shifts - zeropage
ldx #3
ldx #5
tasl2
set_z zp1,0
set_z zps,0
asl zpt
tst_z rASL,fASL,0
dex
bpl tasl2
ldx #3
ldx #5
tasl3
set_z zp1,$ff
set_z zps,$ff
asl zpt
tst_z rASL,fASL,$ff-fnzc
dex
bpl tasl3
ldx #3
ldx #5
tlsr2
set_z zp1,0
set_z zps,0
lsr zpt
tst_z rLSR,fLSR,0
dex
bpl tlsr2
ldx #3
ldx #5
tlsr3
set_z zp1,$ff
set_z zps,$ff
lsr zpt
tst_z rLSR,fLSR,$ff-fnzc
dex
bpl tlsr3
ldx #3
ldx #5
trol2
set_z zp1,0
set_z zps,0
rol zpt
tst_z rROL,fROL,0
dex
bpl trol2
ldx #3
ldx #5
trol3
set_z zp1,$ff-fc
set_z zps,$ff-fc
rol zpt
tst_z rROL,fROL,$ff-fnzc
dex
bpl trol3
ldx #3
ldx #5
trolc2
set_z zp1,fc
set_z zps,fc
rol zpt
tst_z rROLc,fROLc,0
dex
bpl trolc2
ldx #3
ldx #5
trolc3
set_z zp1,$ff
set_z zps,$ff
rol zpt
tst_z rROLc,fROLc,$ff-fnzc
dex
bpl trolc3
ldx #3
ldx #5
tror2
set_z zp1,0
set_z zps,0
ror zpt
tst_z rROR,fROR,0
dex
bpl tror2
ldx #3
ldx #5
tror3
set_z zp1,$ff-fc
set_z zps,$ff-fc
ror zpt
tst_z rROR,fROR,$ff-fnzc
dex
bpl tror3
ldx #3
ldx #5
trorc2
set_z zp1,fc
set_z zps,fc
ror zpt
tst_z rRORc,fRORc,0
dex
bpl trorc2
ldx #3
ldx #5
trorc3
set_z zp1,$ff
set_z zps,$ff
ror zpt
tst_z rRORc,fRORc,$ff-fnzc
dex
@ -4254,91 +4258,91 @@ trorc3
next_test
; shifts - absolute
ldx #3
ldx #5
tasl4
set_abs zp1,0
set_abs zps,0
asl abst
tst_abs rASL,fASL,0
dex
bpl tasl4
ldx #3
ldx #5
tasl5
set_abs zp1,$ff
set_abs zps,$ff
asl abst
tst_abs rASL,fASL,$ff-fnzc
dex
bpl tasl5
ldx #3
ldx #5
tlsr4
set_abs zp1,0
set_abs zps,0
lsr abst
tst_abs rLSR,fLSR,0
dex
bpl tlsr4
ldx #3
ldx #5
tlsr5
set_abs zp1,$ff
set_abs zps,$ff
lsr abst
tst_abs rLSR,fLSR,$ff-fnzc
dex
bpl tlsr5
ldx #3
ldx #5
trol4
set_abs zp1,0
set_abs zps,0
rol abst
tst_abs rROL,fROL,0
dex
bpl trol4
ldx #3
ldx #5
trol5
set_abs zp1,$ff-fc
set_abs zps,$ff-fc
rol abst
tst_abs rROL,fROL,$ff-fnzc
dex
bpl trol5
ldx #3
ldx #5
trolc4
set_abs zp1,fc
set_abs zps,fc
rol abst
tst_abs rROLc,fROLc,0
dex
bpl trolc4
ldx #3
ldx #5
trolc5
set_abs zp1,$ff
set_abs zps,$ff
rol abst
tst_abs rROLc,fROLc,$ff-fnzc
dex
bpl trolc5
ldx #3
ldx #5
tror4
set_abs zp1,0
set_abs zps,0
ror abst
tst_abs rROR,fROR,0
dex
bpl tror4
ldx #3
ldx #5
tror5
set_abs zp1,$ff-fc
set_abs zps,$ff-fc
ror abst
tst_abs rROR,fROR,$ff-fnzc
dex
bpl tror5
ldx #3
ldx #5
trorc4
set_abs zp1,fc
set_abs zps,fc
ror abst
tst_abs rRORc,fRORc,0
dex
bpl trorc4
ldx #3
ldx #5
trorc5
set_abs zp1,$ff
set_abs zps,$ff
ror abst
tst_abs rRORc,fRORc,$ff-fnzc
dex
@ -4346,91 +4350,91 @@ trorc5
next_test
; shifts - zp indexed
ldx #3
ldx #5
tasl6
set_zx zp1,0
set_zx zps,0
asl zpt,x
tst_zx rASL,fASL,0
dex
bpl tasl6
ldx #3
ldx #5
tasl7
set_zx zp1,$ff
set_zx zps,$ff
asl zpt,x
tst_zx rASL,fASL,$ff-fnzc
dex
bpl tasl7
ldx #3
ldx #5
tlsr6
set_zx zp1,0
set_zx zps,0
lsr zpt,x
tst_zx rLSR,fLSR,0
dex
bpl tlsr6
ldx #3
ldx #5
tlsr7
set_zx zp1,$ff
set_zx zps,$ff
lsr zpt,x
tst_zx rLSR,fLSR,$ff-fnzc
dex
bpl tlsr7
ldx #3
ldx #5
trol6
set_zx zp1,0
set_zx zps,0
rol zpt,x
tst_zx rROL,fROL,0
dex
bpl trol6
ldx #3
ldx #5
trol7
set_zx zp1,$ff-fc
set_zx zps,$ff-fc
rol zpt,x
tst_zx rROL,fROL,$ff-fnzc
dex
bpl trol7
ldx #3
ldx #5
trolc6
set_zx zp1,fc
set_zx zps,fc
rol zpt,x
tst_zx rROLc,fROLc,0
dex
bpl trolc6
ldx #3
ldx #5
trolc7
set_zx zp1,$ff
set_zx zps,$ff
rol zpt,x
tst_zx rROLc,fROLc,$ff-fnzc
dex
bpl trolc7
ldx #3
ldx #5
tror6
set_zx zp1,0
set_zx zps,0
ror zpt,x
tst_zx rROR,fROR,0
dex
bpl tror6
ldx #3
ldx #5
tror7
set_zx zp1,$ff-fc
set_zx zps,$ff-fc
ror zpt,x
tst_zx rROR,fROR,$ff-fnzc
dex
bpl tror7
ldx #3
ldx #5
trorc6
set_zx zp1,fc
set_zx zps,fc
ror zpt,x
tst_zx rRORc,fRORc,0
dex
bpl trorc6
ldx #3
ldx #5
trorc7
set_zx zp1,$ff
set_zx zps,$ff
ror zpt,x
tst_zx rRORc,fRORc,$ff-fnzc
dex
@ -4438,91 +4442,91 @@ trorc7
next_test
; shifts - abs indexed
ldx #3
ldx #5
tasl8
set_absx zp1,0
set_absx zps,0
asl abst,x
tst_absx rASL,fASL,0
dex
bpl tasl8
ldx #3
ldx #5
tasl9
set_absx zp1,$ff
set_absx zps,$ff
asl abst,x
tst_absx rASL,fASL,$ff-fnzc
dex
bpl tasl9
ldx #3
ldx #5
tlsr8
set_absx zp1,0
set_absx zps,0
lsr abst,x
tst_absx rLSR,fLSR,0
dex
bpl tlsr8
ldx #3
ldx #5
tlsr9
set_absx zp1,$ff
set_absx zps,$ff
lsr abst,x
tst_absx rLSR,fLSR,$ff-fnzc
dex
bpl tlsr9
ldx #3
ldx #5
trol8
set_absx zp1,0
set_absx zps,0
rol abst,x
tst_absx rROL,fROL,0
dex
bpl trol8
ldx #3
ldx #5
trol9
set_absx zp1,$ff-fc
set_absx zps,$ff-fc
rol abst,x
tst_absx rROL,fROL,$ff-fnzc
dex
bpl trol9
ldx #3
ldx #5
trolc8
set_absx zp1,fc
set_absx zps,fc
rol abst,x
tst_absx rROLc,fROLc,0
dex
bpl trolc8
ldx #3
ldx #5
trolc9
set_absx zp1,$ff
set_absx zps,$ff
rol abst,x
tst_absx rROLc,fROLc,$ff-fnzc
dex
bpl trolc9
ldx #3
ldx #5
tror8
set_absx zp1,0
set_absx zps,0
ror abst,x
tst_absx rROR,fROR,0
dex
bpl tror8
ldx #3
ldx #5
tror9
set_absx zp1,$ff-fc
set_absx zps,$ff-fc
ror abst,x
tst_absx rROR,fROR,$ff-fnzc
dex
bpl tror9
ldx #3
ldx #5
trorc8
set_absx zp1,fc
set_absx zps,fc
ror abst,x
tst_absx rRORc,fRORc,0
dex
bpl trorc8
ldx #3
ldx #5
trorc9
set_absx zp1,$ff
set_absx zps,$ff
ror abst,x
tst_absx rRORc,fRORc,$ff-fnzc
dex
@ -5997,6 +6001,7 @@ break2 ;BRK pass 2
;copy of data to initialize BSS segment
if load_data_direct != 1
zp_init
zps_ db $80,1 ;additional shift pattern to test zero result & flag
zp1_ db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
zp7f_ db $7f ;test pattern for compare
;logical zeropage operands
@ -6048,34 +6053,35 @@ ex_adc_ adc #0 ;execute immediate opcodes
rts
ex_sbc_ sbc #0 ;execute immediate opcodes
rts
;zps db $80,1 ;additional shift patterns test zero result & flag
abs1_ db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
abs7f_ db $7f ;test pattern for compare
;loads
fLDx_ db fn,fn,0,fz ;expected flags for load
fLDx_ db fn,fn,0,fz ;expected flags for load
;shifts
rASL_ ;expected result ASL & ROL -carry
rROL_ db $86,$04,$82,0 ; "
rROLc_ db $87,$05,$83,1 ;expected result ROL +carry
rLSR_ ;expected result LSR & ROR -carry
rROR_ db $61,$41,$20,0 ; "
rRORc_ db $e1,$c1,$a0,$80 ;expected result ROR +carry
fASL_ ;expected flags for shifts
fROL_ db fnc,fc,fn,fz ;no carry in
fROLc_ db fnc,fc,fn,0 ;carry in
rASL_ ;expected result ASL & ROL -carry
rROL_ db 0,2,$86,$04,$82,0
rROLc_ db 1,3,$87,$05,$83,1 ;expected result ROL +carry
rLSR_ ;expected result LSR & ROR -carry
rROR_ db $40,0,$61,$41,$20,0
rRORc_ db $c0,$80,$e1,$c1,$a0,$80 ;expected result ROR +carry
fASL_ ;expected flags for shifts
fROL_ db fzc,0,fnc,fc,fn,fz ;no carry in
fROLc_ db fc,0,fnc,fc,fn,0 ;carry in
fLSR_
fROR_ db fc,0,fc,fz ;no carry in
fRORc_ db fnc,fn,fnc,fn ;carry in
fROR_ db 0,fzc,fc,0,fc,fz ;no carry in
fRORc_ db fn,fnc,fnc,fn,fnc,fn ;carry in
;increments (decrements)
rINC_ db $7f,$80,$ff,0,1 ;expected result for INC/DEC
fINC_ db 0,fn,fn,fz,0 ;expected flags for INC/DEC
rINC_ db $7f,$80,$ff,0,1 ;expected result for INC/DEC
fINC_ db 0,fn,fn,fz,0 ;expected flags for INC/DEC
;logical memory operand
absOR_ db 0,$1f,$71,$80 ;test pattern for OR
absAN_ db $0f,$ff,$7f,$80 ;test pattern for AND
absEO_ db $ff,$0f,$8f,$8f ;test pattern for EOR
absOR_ db 0,$1f,$71,$80 ;test pattern for OR
absAN_ db $0f,$ff,$7f,$80 ;test pattern for AND
absEO_ db $ff,$0f,$8f,$8f ;test pattern for EOR
;logical accu operand
absORa_ db 0,$f1,$1f,0 ;test pattern for OR
absANa_ db $f0,$ff,$ff,$ff ;test pattern for AND
absEOa_ db $ff,$f0,$f0,$0f ;test pattern for EOR
absORa_ db 0,$f1,$1f,0 ;test pattern for OR
absANa_ db $f0,$ff,$ff,$ff ;test pattern for AND
absEOa_ db $ff,$f0,$f0,$0f ;test pattern for EOR
;logical results
absrlo_ db 0,$ff,$7f,$80
absflo_ db fz,fn,0,fn
@ -6100,4 +6106,4 @@ vec_bss equ $fffa
endif
end start

View File

@ -19,7 +19,7 @@
; This program is designed to test IRQ and NMI of a 6502 emulator. It requires
; an internal or external feedback register to the IRQ & NMI inputs
;
;
; version 15-aug-2014
; contact info at http://2m5.de or email K@2m5.de
;
@ -83,10 +83,10 @@ D_clear = 0 ;0 = not cleared (NMOS), 1 = cleared (CMOS)
;configure memory - try to stay away from memory used by the system
;zero_page memory start address, 6 consecutive Bytes required
zero_page = $a
zero_page = $0
;data_segment memory start address, 4 consecutive Bytes required
data_segment = $200
data_segment = $200
;code_segment memory start address
code_segment = $400
@ -205,7 +205,7 @@ zp_bss
;fixed stack locations
lst_f equ $1fe ;last flags before interrupt
lst_a equ $1ff ;last accumulator before interrupt
org data_segment
;concurrent NMI, IRQ & BRK test result
nmi_count ds 1 ;lowest number handled first, $ff = never
@ -222,7 +222,7 @@ start cld
sta I_src
ldx #$ff
txs
;initialize I/O for report channel
if report = 1
jsr report_init
@ -263,7 +263,7 @@ I_clr macro ibit ;ibit = interrupt bit
and #I_filter
ora #(1<<IRQ_bit)
sta I_ddr
endif
endif
else ;open collector, 0 -> I_DDR or I_port to force interrupt
if I_ddr != 0 ;with DDR
I_set macro ibit ;ibit = interrupt bit
@ -278,7 +278,7 @@ I_set macro ibit ;ibit = interrupt bit
I_clr macro ibit ;ibit = interrupt bit
lda I_ddr ;turn off interrupt by bit
and #I_filter-(1<<ibit)
sta I_ddr
sta I_ddr
endm
I_clr IRQ_bit ;turn off IRQ
lda I_port ;precharge IRQ
@ -329,7 +329,7 @@ I_clr macro ibit ;ibit = interrupt bit
and #I_filter
ora #(1<<IRQ_bit|1<<NMI_bit)
sta I_ddr
endif
endif
else ;open collector, 0 -> I_DDR or I_port to force interrupt
if I_ddr != 0 ;with DDR
I_set macro ibit ;ibit = interrupt bit
@ -348,7 +348,7 @@ I_set macro ibit ;ibit = interrupt bit
I_clr macro ibit ;ibit = interrupt bit
lda I_ddr ;turn off interrupt by bit
and #I_filter-(1<<ibit)
sta I_ddr
sta I_ddr
endm
I_clr IRQ_bit ;turn off IRQ & NMI
I_clr NMI_bit
@ -379,7 +379,7 @@ I_clr macro ibit ;ibit = interrupt bit
endif
endif
endif
; IRQ integrity test
; test for clear flags seen in IRQ vector
lda #2 ;set expected interrupt source IRQ
@ -633,7 +633,7 @@ I_clr macro ibit ;ibit = interrupt bit
ldx #0
lda #0
sta I_src
push_stat intdis
push_stat intdis
I_set IRQ_bit ;IRQ pending
inx
inx
@ -657,7 +657,7 @@ I_clr macro ibit ;ibit = interrupt bit
sta nmi_count
sta irq_count
sta brk_count
push_stat 0
push_stat 0
I_set IRQ_bit ;trigger IRQ
else
; NMI integrity test
@ -782,7 +782,7 @@ I_clr macro ibit ;ibit = interrupt bit
ldx #0
lda #4 ;set expected interrupt NMI only
sta I_src
push_stat intdis
push_stat intdis
I_set 8 ;both interrupts pending
inx
inx
@ -825,21 +825,21 @@ I_clr macro ibit ;ibit = interrupt bit
;may fail due to a bug on a real NMOS 6502 - NMI could mask BRK
trap_ne ;lost an interrupt
; S U C C E S S ************************************************
; -------------
; S U C C E S S ************************************************
; -------------
success ;if you get here everything went well
; -------------
; S U C C E S S ************************************************
; -------------
; S U C C E S S ************************************************
; check data_segment +0 to +2 for sequence of concurrent interrupts
; e.g. 0x200 = NMI, 0x201 = IRQ, 0x202 = BRK, lower values = earlier
jmp start ;run again
jmp start ;run again
; manual tests for the WAI opcode of the 65c02
wai macro
wai macro
db $cb ;WAI opcode
endm
; requires single step operation, report = 0
; set PC to the 1st instruction of the test
; step to the WAI opcode, then manually tie the IRQ input low
@ -860,7 +860,7 @@ wai macro
trap_ne ;skipped opcodes!
success
; WAI with interrupts enabled
ldx #$ff
txs
@ -878,13 +878,13 @@ wai macro
trap_ne ;skipped opcodes!
success
; manual test for the STP opcode of the 65c02
stp macro
stp macro
db $db ;STP opcode
endm
; set PC to the 1st instruction of the test, then run
nop
nop
@ -916,7 +916,7 @@ nmi_trap
pha
sta nmi_f
lda I_src ;NMI expected?
and #4
and #4
trap_eq ;unexpexted NMI - check stack for conditions
pla ;test I-flag was set
pha
@ -925,7 +925,7 @@ nmi_trap
pla ;return with other flags reversed
eor #m8-fai-decmode
pha
tsx
tsx
lda $102,x ;test break on stack
and #break
trap_ne ;unexpected B-flag! - this may fail on a real 6502
@ -933,7 +933,7 @@ nmi_trap
lda I_src ;mark expected NMI has occured
and #$ff-4
sta I_src
I_clr NMI_bit
I_clr NMI_bit
ldx nmi_x
inx
stx nmi_count
@ -944,7 +944,7 @@ nmi_trap
res_trap
trap ;unexpected RESET
dey
dey
irq_trap ;BRK & IRQ test
@ -958,7 +958,7 @@ irq_trap ;BRK & IRQ test
pha
sta irq_f
lda I_src ;IRQ expected?
and #3
and #3
trap_eq ;unexpexted IRQ/BRK - check stack for conditions
pla ;test I-flag was set
pha
@ -966,26 +966,26 @@ irq_trap ;BRK & IRQ test
trap_eq ;I-flag not set
pla ;return with other flags reversed
eor #m8-fai-decmode
pha
pha
tsx
lda $102,x ;test break on stack
and #break
bne brk_trap
lda I_src ;IRQ expected?
and #2
and #2
trap_eq ;unexpexted IRQ - check stack for conditions
lda I_src ;mark expected IRQ has occured
and #$ff-2
sta I_src
I_clr IRQ_bit
I_clr IRQ_bit
ldx irq_x
inx
stx irq_count
lda #'Q' ;mark (IR)Q
plp ;should be reversed by rti
rti
brk_trap
lda I_src ;break expected?
and #1
@ -995,18 +995,18 @@ brk_trap
sta I_src
ldx irq_x
inx
stx brk_count
stx brk_count
lda irq_a
lda #'K' ;mark (BR)K
plp ;should be reversed by rti
rti
if report = 1
rep_int = 1
include "report.i65"
endif
;system vectors
if (load_data_direct = 1)
org $fffa
@ -1020,7 +1020,6 @@ vec_bss equ $fffa
dw res_trap
dw irq_trap
endif
end start

View File

@ -0,0 +1,356 @@
; Verify decimal mode behavior
; Written by Bruce Clark. This code is public domain.
; see http://www.6502.org/tutorials/decimal_mode.html
;
; Returns:
; ERROR = 0 if the test passed
; ERROR = 1 if the test failed
; modify the code at the DONE label for desired program end
;
; This routine requires 17 bytes of RAM -- 1 byte each for:
; AR, CF, DA, DNVZC, ERROR, HA, HNVZC, N1, N1H, N1L, N2, N2L, NF, VF, and ZF
; and 2 bytes for N2H
;
; Variables:
; N1 and N2 are the two numbers to be added or subtracted
; N1H, N1L, N2H, and N2L are the upper 4 bits and lower 4 bits of N1 and N2
; DA and DNVZC are the actual accumulator and flag results in decimal mode
; HA and HNVZC are the accumulator and flag results when N1 and N2 are
; added or subtracted using binary arithmetic
; AR, NF, VF, ZF, and CF are the predicted decimal mode accumulator and
; flag results, calculated using binary arithmetic
;
; This program takes approximately 1 minute at 1 MHz (a few seconds more on
; a 65C02 than a 6502 or 65816)
;
; Configuration:
cputype = 1 ; 0 = 6502, 1 = 65C02, 2 = 65C816
vld_bcd = 0 ; 0 = allow invalid bcd, 1 = valid bcd only
chk_a = 1 ; check accumulator
chk_n = 0 ; check sign (negative) flag
chk_v = 0 ; check overflow flag
chk_z = 0 ; check zero flag
chk_c = 1 ; check carry flag
end_of_test macro
brk
; db $db ;execute 65C02 stop instruction
endm
bss
org 0
; operands - register Y = carry in
N1 ds 1
N2 ds 1
; binary result
HA ds 1
HNVZC ds 1
;04
; decimal result
DA ds 1
DNVZC ds 1
; predicted results
AR ds 1
NF ds 1
;08
VF ds 1
ZF ds 1
CF ds 1
ERROR ds 1
;0C
; workspace
N1L ds 1
N1H ds 1
N2L ds 1
N2H ds 2
code
org $200
TEST ldy #1 ; initialize Y (used to loop through carry flag values)
sty ERROR ; store 1 in ERROR until the test passes
lda #0 ; initialize N1 and N2
sta N1
sta N2
LOOP1 lda N2 ; N2L = N2 & $0F
and #$0F ; [1] see text
if vld_bcd = 1
cmp #$0a
bcs NEXT2
endif
sta N2L
lda N2 ; N2H = N2 & $F0
and #$F0 ; [2] see text
if vld_bcd = 1
cmp #$a0
bcs NEXT2
endif
sta N2H
ora #$0F ; N2H+1 = (N2 & $F0) + $0F
sta N2H+1
LOOP2 lda N1 ; N1L = N1 & $0F
and #$0F ; [3] see text
if vld_bcd = 1
cmp #$0a
bcs NEXT1
endif
sta N1L
lda N1 ; N1H = N1 & $F0
and #$F0 ; [4] see text
if vld_bcd = 1
cmp #$a0
bcs NEXT1
endif
sta N1H
jsr ADD
jsr A6502
jsr COMPARE
bne DONE
jsr SUB
jsr S6502
jsr COMPARE
bne DONE
NEXT1 inc N1 ; [5] see text
bne LOOP2 ; loop through all 256 values of N1
NEXT2 inc N2 ; [6] see text
bne LOOP1 ; loop through all 256 values of N2
dey
bpl LOOP1 ; loop through both values of the carry flag
lda #0 ; test passed, so store 0 in ERROR
sta ERROR
DONE
end_of_test
; Calculate the actual decimal mode accumulator and flags, the accumulator
; and flag results when N1 is added to N2 using binary arithmetic, the
; predicted accumulator result, the predicted carry flag, and the predicted
; V flag
;
ADD sed ; decimal mode
cpy #1 ; set carry if Y = 1, clear carry if Y = 0
lda N1
adc N2
sta DA ; actual accumulator result in decimal mode
php
pla
sta DNVZC ; actual flags result in decimal mode
cld ; binary mode
cpy #1 ; set carry if Y = 1, clear carry if Y = 0
lda N1
adc N2
sta HA ; accumulator result of N1+N2 using binary arithmetic
php
pla
sta HNVZC ; flags result of N1+N2 using binary arithmetic
cpy #1
lda N1L
adc N2L
cmp #$0A
ldx #0
bcc A1
inx
adc #5 ; add 6 (carry is set)
and #$0F
sec
A1 ora N1H
;
; if N1L + N2L < $0A, then add N2 & $F0
; if N1L + N2L >= $0A, then add (N2 & $F0) + $0F + 1 (carry is set)
;
adc N2H,x
php
bcs A2
cmp #$A0
bcc A3
A2 adc #$5F ; add $60 (carry is set)
sec
A3 sta AR ; predicted accumulator result
php
pla
sta CF ; predicted carry result
pla
;
; note that all 8 bits of the P register are stored in VF
;
sta VF ; predicted V flags
rts
; Calculate the actual decimal mode accumulator and flags, and the
; accumulator and flag results when N2 is subtracted from N1 using binary
; arithmetic
;
SUB sed ; decimal mode
cpy #1 ; set carry if Y = 1, clear carry if Y = 0
lda N1
sbc N2
sta DA ; actual accumulator result in decimal mode
php
pla
sta DNVZC ; actual flags result in decimal mode
cld ; binary mode
cpy #1 ; set carry if Y = 1, clear carry if Y = 0
lda N1
sbc N2
sta HA ; accumulator result of N1-N2 using binary arithmetic
php
pla
sta HNVZC ; flags result of N1-N2 using binary arithmetic
rts
if cputype != 1
; Calculate the predicted SBC accumulator result for the 6502 and 65816
;
SUB1 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
lda N1L
sbc N2L
ldx #0
bcs S11
inx
sbc #5 ; subtract 6 (carry is clear)
and #$0F
clc
S11 ora N1H
;
; if N1L - N2L >= 0, then subtract N2 & $F0
; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear)
;
sbc N2H,x
bcs S12
sbc #$5F ; subtract $60 (carry is clear)
S12 sta AR
rts
endif
if cputype = 1
; Calculate the predicted SBC accumulator result for the 6502 and 65C02
;
SUB2 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
lda N1L
sbc N2L
ldx #0
bcs S21
inx
and #$0F
clc
S21 ora N1H
;
; if N1L - N2L >= 0, then subtract N2 & $F0
; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear)
;
sbc N2H,x
bcs S22
sbc #$5F ; subtract $60 (carry is clear)
S22 cpx #0
beq S23
sbc #6
S23 sta AR ; predicted accumulator result
rts
endif
; Compare accumulator actual results to predicted results
;
; Return:
; Z flag = 1 (BEQ branch) if same
; Z flag = 0 (BNE branch) if different
;
COMPARE
if chk_a = 1
lda DA
cmp AR
bne C1
endif
if chk_n = 1
lda DNVZC ; [7] see text
eor NF
and #$80 ; mask off N flag
bne C1
endif
if chk_v = 1
lda DNVZC ; [8] see text
eor VF
and #$40 ; mask off V flag
bne C1 ; [9] see text
endif
if chk_z = 1
lda DNVZC
eor ZF ; mask off Z flag
and #2
bne C1 ; [10] see text
endif
if chk_c = 1
lda DNVZC
eor CF
and #1 ; mask off C flag
endif
C1 rts
; These routines store the predicted values for ADC and SBC for the 6502,
; 65C02, and 65816 in AR, CF, NF, VF, and ZF
if cputype = 0
A6502 lda VF ; 6502
;
; since all 8 bits of the P register were stored in VF, bit 7 of VF contains
; the N flag for NF
;
sta NF
lda HNVZC
sta ZF
rts
S6502 jsr SUB1
lda HNVZC
sta NF
sta VF
sta ZF
sta CF
rts
endif
if cputype = 1
A6502 lda AR ; 65C02
php
pla
sta NF
sta ZF
rts
S6502 jsr SUB2
lda AR
php
pla
sta NF
sta ZF
lda HNVZC
sta VF
sta CF
rts
endif
if cputype = 2
A6502 lda AR ; 65C816
php
pla
sta NF
sta ZF
rts
S6502 jsr SUB1
lda AR
php
pla
sta NF
sta ZF
lda HNVZC
sta VF
sta CF
rts
endif
end TEST

Binary file not shown.

View File

@ -0,0 +1,369 @@
AS65 Assembler for R6502 [1.42]. Copyright 1994-2007, Frank A. Kingswood Page 1
----------------------------------------------------- 6502_decimal_test.a65 ------------------------------------------------------
356 lines read, no errors in pass 1.
; Verify decimal mode behavior
; Written by Bruce Clark. This code is public domain.
; see http://www.6502.org/tutorials/decimal_mode.html
;
; Returns:
; ERROR = 0 if the test passed
; ERROR = 1 if the test failed
; modify the code at the DONE label for desired program end
;
; This routine requires 17 bytes of RAM -- 1 byte each for:
; AR, CF, DA, DNVZC, ERROR, HA, HNVZC, N1, N1H, N1L, N2, N2L, NF, VF, and ZF
; and 2 bytes for N2H
;
; Variables:
; N1 and N2 are the two numbers to be added or subtracted
; N1H, N1L, N2H, and N2L are the upper 4 bits and lower 4 bits of N1 and N2
; DA and DNVZC are the actual accumulator and flag results in decimal mode
; HA and HNVZC are the accumulator and flag results when N1 and N2 are
; added or subtracted using binary arithmetic
; AR, NF, VF, ZF, and CF are the predicted decimal mode accumulator and
; flag results, calculated using binary arithmetic
;
; This program takes approximately 1 minute at 1 MHz (a few seconds more on
; a 65C02 than a 6502 or 65816)
;
; Configuration:
0000 = cputype = 0 ; 0 = 6502, 1 = 65C02, 2 = 65C816
0000 = vld_bcd = 0 ; 0 = allow invalid bcd, 1 = valid bcd only
0001 = chk_a = 1 ; check accumulator
0000 = chk_n = 0 ; check sign (negative) flag
0000 = chk_v = 0 ; check overflow flag
0000 = chk_z = 0 ; check zero flag
0001 = chk_c = 1 ; check carry flag
end_of_test macro
brk
; db $db ;execute 65C02 stop instruction
endm
bss
0000 = org 0
; operands - register Y = carry in
0000 = N1 ds 1
0001 = N2 ds 1
; binary result
0002 = HA ds 1
0003 = HNVZC ds 1
;04
; decimal result
0004 = DA ds 1
0005 = DNVZC ds 1
; predicted results
0006 = AR ds 1
0007 = NF ds 1
;08
0008 = VF ds 1
0009 = ZF ds 1
000a = CF ds 1
000b = ERROR ds 1
;0C
; workspace
000c = N1L ds 1
000d = N1H ds 1
000e = N2L ds 1
000f = N2H ds 2
code
0200 = org $200
0200 : a001 TEST ldy #1 ; initialize Y (used to loop through carry flag values)
0202 : 840b sty ERROR ; store 1 in ERROR until the test passes
0204 : a900 lda #0 ; initialize N1 and N2
0206 : 8500 sta N1
0208 : 8501 sta N2
020a : a501 LOOP1 lda N2 ; N2L = N2 & $0F
020c : 290f and #$0F ; [1] see text
if vld_bcd = 1
cmp #$0a
bcs NEXT2
endif
020e : 850e sta N2L
0210 : a501 lda N2 ; N2H = N2 & $F0
0212 : 29f0 and #$F0 ; [2] see text
if vld_bcd = 1
cmp #$a0
bcs NEXT2
endif
0214 : 850f sta N2H
0216 : 090f ora #$0F ; N2H+1 = (N2 & $F0) + $0F
0218 : 8510 sta N2H+1
021a : a500 LOOP2 lda N1 ; N1L = N1 & $0F
021c : 290f and #$0F ; [3] see text
if vld_bcd = 1
cmp #$0a
bcs NEXT1
endif
021e : 850c sta N1L
0220 : a500 lda N1 ; N1H = N1 & $F0
0222 : 29f0 and #$F0 ; [4] see text
if vld_bcd = 1
cmp #$a0
bcs NEXT1
endif
0224 : 850d sta N1H
0226 : 204c02 jsr ADD
0229 : 20d302 jsr A6502
022c : 20c602 jsr COMPARE
022f : d01a bne DONE
0231 : 209002 jsr SUB
0234 : 20dc02 jsr S6502
0237 : 20c602 jsr COMPARE
023a : d00f bne DONE
023c : e600 NEXT1 inc N1 ; [5] see text
023e : d0da bne LOOP2 ; loop through all 256 values of N1
0240 : e601 NEXT2 inc N2 ; [6] see text
0242 : d0c6 bne LOOP1 ; loop through all 256 values of N2
0244 : 88 dey
0245 : 10c3 bpl LOOP1 ; loop through both values of the carry flag
0247 : a900 lda #0 ; test passed, so store 0 in ERROR
0249 : 850b sta ERROR
024b : DONE
end_of_test
024b : 00 > brk
> ; db $db ;execute 65C02 stop instruction
; Calculate the actual decimal mode accumulator and flags, the accumulator
; and flag results when N1 is added to N2 using binary arithmetic, the
; predicted accumulator result, the predicted carry flag, and the predicted
; V flag
;
024c : f8 ADD sed ; decimal mode
024d : c001 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
024f : a500 lda N1
0251 : 6501 adc N2
0253 : 8504 sta DA ; actual accumulator result in decimal mode
0255 : 08 php
0256 : 68 pla
0257 : 8505 sta DNVZC ; actual flags result in decimal mode
0259 : d8 cld ; binary mode
025a : c001 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
025c : a500 lda N1
025e : 6501 adc N2
0260 : 8502 sta HA ; accumulator result of N1+N2 using binary arithmetic
0262 : 08 php
0263 : 68 pla
0264 : 8503 sta HNVZC ; flags result of N1+N2 using binary arithmetic
0266 : c001 cpy #1
0268 : a50c lda N1L
026a : 650e adc N2L
026c : c90a cmp #$0A
026e : a200 ldx #0
0270 : 9006 bcc A1
0272 : e8 inx
0273 : 6905 adc #5 ; add 6 (carry is set)
0275 : 290f and #$0F
0277 : 38 sec
0278 : 050d A1 ora N1H
;
; if N1L + N2L < $0A, then add N2 & $F0
; if N1L + N2L >= $0A, then add (N2 & $F0) + $0F + 1 (carry is set)
;
027a : 750f adc N2H,x
027c : 08 php
027d : b004 bcs A2
027f : c9a0 cmp #$A0
0281 : 9003 bcc A3
0283 : 695f A2 adc #$5F ; add $60 (carry is set)
0285 : 38 sec
0286 : 8506 A3 sta AR ; predicted accumulator result
0288 : 08 php
0289 : 68 pla
028a : 850a sta CF ; predicted carry result
028c : 68 pla
;
; note that all 8 bits of the P register are stored in VF
;
028d : 8508 sta VF ; predicted V flags
028f : 60 rts
; Calculate the actual decimal mode accumulator and flags, and the
; accumulator and flag results when N2 is subtracted from N1 using binary
; arithmetic
;
0290 : f8 SUB sed ; decimal mode
0291 : c001 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
0293 : a500 lda N1
0295 : e501 sbc N2
0297 : 8504 sta DA ; actual accumulator result in decimal mode
0299 : 08 php
029a : 68 pla
029b : 8505 sta DNVZC ; actual flags result in decimal mode
029d : d8 cld ; binary mode
029e : c001 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
02a0 : a500 lda N1
02a2 : e501 sbc N2
02a4 : 8502 sta HA ; accumulator result of N1-N2 using binary arithmetic
02a6 : 08 php
02a7 : 68 pla
02a8 : 8503 sta HNVZC ; flags result of N1-N2 using binary arithmetic
02aa : 60 rts
if cputype != 1
; Calculate the predicted SBC accumulator result for the 6502 and 65816
;
02ab : c001 SUB1 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
02ad : a50c lda N1L
02af : e50e sbc N2L
02b1 : a200 ldx #0
02b3 : b006 bcs S11
02b5 : e8 inx
02b6 : e905 sbc #5 ; subtract 6 (carry is clear)
02b8 : 290f and #$0F
02ba : 18 clc
02bb : 050d S11 ora N1H
;
; if N1L - N2L >= 0, then subtract N2 & $F0
; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear)
;
02bd : f50f sbc N2H,x
02bf : b002 bcs S12
02c1 : e95f sbc #$5F ; subtract $60 (carry is clear)
02c3 : 8506 S12 sta AR
02c5 : 60 rts
endif
if cputype = 1
; Calculate the predicted SBC accumulator result for the 6502 and 65C02
;
SUB2 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
lda N1L
sbc N2L
ldx #0
bcs S21
inx
and #$0F
clc
S21 ora N1H
;
; if N1L - N2L >= 0, then subtract N2 & $F0
; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear)
;
sbc N2H,x
bcs S22
sbc #$5F ; subtract $60 (carry is clear)
S22 cpx #0
beq S23
sbc #6
S23 sta AR ; predicted accumulator result
rts
endif
; Compare accumulator actual results to predicted results
;
; Return:
; Z flag = 1 (BEQ branch) if same
; Z flag = 0 (BNE branch) if different
;
02c6 : COMPARE
if chk_a = 1
02c6 : a504 lda DA
02c8 : c506 cmp AR
02ca : d006 bne C1
endif
if chk_n = 1
lda DNVZC ; [7] see text
eor NF
and #$80 ; mask off N flag
bne C1
endif
if chk_v = 1
lda DNVZC ; [8] see text
eor VF
and #$40 ; mask off V flag
bne C1 ; [9] see text
endif
if chk_z = 1
lda DNVZC
eor ZF ; mask off Z flag
and #2
bne C1 ; [10] see text
endif
if chk_c = 1
02cc : a505 lda DNVZC
02ce : 450a eor CF
02d0 : 2901 and #1 ; mask off C flag
endif
02d2 : 60 C1 rts
; These routines store the predicted values for ADC and SBC for the 6502,
; 65C02, and 65816 in AR, CF, NF, VF, and ZF
if cputype = 0
02d3 : a508 A6502 lda VF ; 6502
;
; since all 8 bits of the P register were stored in VF, bit 7 of VF contains
; the N flag for NF
;
02d5 : 8507 sta NF
02d7 : a503 lda HNVZC
02d9 : 8509 sta ZF
02db : 60 rts
02dc : 20ab02 S6502 jsr SUB1
02df : a503 lda HNVZC
02e1 : 8507 sta NF
02e3 : 8508 sta VF
02e5 : 8509 sta ZF
02e7 : 850a sta CF
02e9 : 60 rts
endif
if cputype = 1
A6502 lda AR ; 65C02
php
pla
sta NF
sta ZF
rts
S6502 jsr SUB2
lda AR
php
pla
sta NF
sta ZF
lda HNVZC
sta VF
sta CF
rts
endif
if cputype = 2
A6502 lda AR ; 65C816
php
pla
sta NF
sta ZF
rts
S6502 jsr SUB1
lda AR
php
pla
sta NF
sta ZF
lda HNVZC
sta VF
sta CF
rts
endif
02dc = end TEST
No errors in pass 2.
Wrote binary from address $0200 through $02e9.
Total size 234 bytes.
Program start address is at $0200 (512).

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,369 @@
AS65 Assembler for R6502 [1.42]. Copyright 1994-2007, Frank A. Kingswood Page 1
----------------------------------------------------- 65C02_decimal_test.a65 -----------------------------------------------------
356 lines read, no errors in pass 1.
; Verify decimal mode behavior
; Written by Bruce Clark. This code is public domain.
; see http://www.6502.org/tutorials/decimal_mode.html
;
; Returns:
; ERROR = 0 if the test passed
; ERROR = 1 if the test failed
; modify the code at the DONE label for desired program end
;
; This routine requires 17 bytes of RAM -- 1 byte each for:
; AR, CF, DA, DNVZC, ERROR, HA, HNVZC, N1, N1H, N1L, N2, N2L, NF, VF, and ZF
; and 2 bytes for N2H
;
; Variables:
; N1 and N2 are the two numbers to be added or subtracted
; N1H, N1L, N2H, and N2L are the upper 4 bits and lower 4 bits of N1 and N2
; DA and DNVZC are the actual accumulator and flag results in decimal mode
; HA and HNVZC are the accumulator and flag results when N1 and N2 are
; added or subtracted using binary arithmetic
; AR, NF, VF, ZF, and CF are the predicted decimal mode accumulator and
; flag results, calculated using binary arithmetic
;
; This program takes approximately 1 minute at 1 MHz (a few seconds more on
; a 65C02 than a 6502 or 65816)
;
; Configuration:
0001 = cputype = 1 ; 0 = 6502, 1 = 65C02, 2 = 65C816
0000 = vld_bcd = 0 ; 0 = allow invalid bcd, 1 = valid bcd only
0001 = chk_a = 1 ; check accumulator
0000 = chk_n = 0 ; check sign (negative) flag
0000 = chk_v = 0 ; check overflow flag
0000 = chk_z = 0 ; check zero flag
0001 = chk_c = 1 ; check carry flag
end_of_test macro
brk
; db $db ;execute 65C02 stop instruction
endm
bss
0000 = org 0
; operands - register Y = carry in
0000 = N1 ds 1
0001 = N2 ds 1
; binary result
0002 = HA ds 1
0003 = HNVZC ds 1
;04
; decimal result
0004 = DA ds 1
0005 = DNVZC ds 1
; predicted results
0006 = AR ds 1
0007 = NF ds 1
;08
0008 = VF ds 1
0009 = ZF ds 1
000a = CF ds 1
000b = ERROR ds 1
;0C
; workspace
000c = N1L ds 1
000d = N1H ds 1
000e = N2L ds 1
000f = N2H ds 2
code
0200 = org $200
0200 : a001 TEST ldy #1 ; initialize Y (used to loop through carry flag values)
0202 : 840b sty ERROR ; store 1 in ERROR until the test passes
0204 : a900 lda #0 ; initialize N1 and N2
0206 : 8500 sta N1
0208 : 8501 sta N2
020a : a501 LOOP1 lda N2 ; N2L = N2 & $0F
020c : 290f and #$0F ; [1] see text
if vld_bcd = 1
cmp #$0a
bcs NEXT2
endif
020e : 850e sta N2L
0210 : a501 lda N2 ; N2H = N2 & $F0
0212 : 29f0 and #$F0 ; [2] see text
if vld_bcd = 1
cmp #$a0
bcs NEXT2
endif
0214 : 850f sta N2H
0216 : 090f ora #$0F ; N2H+1 = (N2 & $F0) + $0F
0218 : 8510 sta N2H+1
021a : a500 LOOP2 lda N1 ; N1L = N1 & $0F
021c : 290f and #$0F ; [3] see text
if vld_bcd = 1
cmp #$0a
bcs NEXT1
endif
021e : 850c sta N1L
0220 : a500 lda N1 ; N1H = N1 & $F0
0222 : 29f0 and #$F0 ; [4] see text
if vld_bcd = 1
cmp #$a0
bcs NEXT1
endif
0224 : 850d sta N1H
0226 : 204c02 jsr ADD
0229 : 20d702 jsr A6502
022c : 20ca02 jsr COMPARE
022f : d01a bne DONE
0231 : 209002 jsr SUB
0234 : 20e002 jsr S6502
0237 : 20ca02 jsr COMPARE
023a : d00f bne DONE
023c : e600 NEXT1 inc N1 ; [5] see text
023e : d0da bne LOOP2 ; loop through all 256 values of N1
0240 : e601 NEXT2 inc N2 ; [6] see text
0242 : d0c6 bne LOOP1 ; loop through all 256 values of N2
0244 : 88 dey
0245 : 10c3 bpl LOOP1 ; loop through both values of the carry flag
0247 : a900 lda #0 ; test passed, so store 0 in ERROR
0249 : 850b sta ERROR
024b : DONE
end_of_test
024b : 00 > brk
> ; db $db ;execute 65C02 stop instruction
; Calculate the actual decimal mode accumulator and flags, the accumulator
; and flag results when N1 is added to N2 using binary arithmetic, the
; predicted accumulator result, the predicted carry flag, and the predicted
; V flag
;
024c : f8 ADD sed ; decimal mode
024d : c001 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
024f : a500 lda N1
0251 : 6501 adc N2
0253 : 8504 sta DA ; actual accumulator result in decimal mode
0255 : 08 php
0256 : 68 pla
0257 : 8505 sta DNVZC ; actual flags result in decimal mode
0259 : d8 cld ; binary mode
025a : c001 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
025c : a500 lda N1
025e : 6501 adc N2
0260 : 8502 sta HA ; accumulator result of N1+N2 using binary arithmetic
0262 : 08 php
0263 : 68 pla
0264 : 8503 sta HNVZC ; flags result of N1+N2 using binary arithmetic
0266 : c001 cpy #1
0268 : a50c lda N1L
026a : 650e adc N2L
026c : c90a cmp #$0A
026e : a200 ldx #0
0270 : 9006 bcc A1
0272 : e8 inx
0273 : 6905 adc #5 ; add 6 (carry is set)
0275 : 290f and #$0F
0277 : 38 sec
0278 : 050d A1 ora N1H
;
; if N1L + N2L < $0A, then add N2 & $F0
; if N1L + N2L >= $0A, then add (N2 & $F0) + $0F + 1 (carry is set)
;
027a : 750f adc N2H,x
027c : 08 php
027d : b004 bcs A2
027f : c9a0 cmp #$A0
0281 : 9003 bcc A3
0283 : 695f A2 adc #$5F ; add $60 (carry is set)
0285 : 38 sec
0286 : 8506 A3 sta AR ; predicted accumulator result
0288 : 08 php
0289 : 68 pla
028a : 850a sta CF ; predicted carry result
028c : 68 pla
;
; note that all 8 bits of the P register are stored in VF
;
028d : 8508 sta VF ; predicted V flags
028f : 60 rts
; Calculate the actual decimal mode accumulator and flags, and the
; accumulator and flag results when N2 is subtracted from N1 using binary
; arithmetic
;
0290 : f8 SUB sed ; decimal mode
0291 : c001 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
0293 : a500 lda N1
0295 : e501 sbc N2
0297 : 8504 sta DA ; actual accumulator result in decimal mode
0299 : 08 php
029a : 68 pla
029b : 8505 sta DNVZC ; actual flags result in decimal mode
029d : d8 cld ; binary mode
029e : c001 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
02a0 : a500 lda N1
02a2 : e501 sbc N2
02a4 : 8502 sta HA ; accumulator result of N1-N2 using binary arithmetic
02a6 : 08 php
02a7 : 68 pla
02a8 : 8503 sta HNVZC ; flags result of N1-N2 using binary arithmetic
02aa : 60 rts
if cputype != 1
; Calculate the predicted SBC accumulator result for the 6502 and 65816
;
SUB1 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
lda N1L
sbc N2L
ldx #0
bcs S11
inx
sbc #5 ; subtract 6 (carry is clear)
and #$0F
clc
S11 ora N1H
;
; if N1L - N2L >= 0, then subtract N2 & $F0
; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear)
;
sbc N2H,x
bcs S12
sbc #$5F ; subtract $60 (carry is clear)
S12 sta AR
rts
endif
if cputype = 1
; Calculate the predicted SBC accumulator result for the 6502 and 65C02
;
02ab : c001 SUB2 cpy #1 ; set carry if Y = 1, clear carry if Y = 0
02ad : a50c lda N1L
02af : e50e sbc N2L
02b1 : a200 ldx #0
02b3 : b004 bcs S21
02b5 : e8 inx
02b6 : 290f and #$0F
02b8 : 18 clc
02b9 : 050d S21 ora N1H
;
; if N1L - N2L >= 0, then subtract N2 & $F0
; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear)
;
02bb : f50f sbc N2H,x
02bd : b002 bcs S22
02bf : e95f sbc #$5F ; subtract $60 (carry is clear)
02c1 : e000 S22 cpx #0
02c3 : f002 beq S23
02c5 : e906 sbc #6
02c7 : 8506 S23 sta AR ; predicted accumulator result
02c9 : 60 rts
endif
; Compare accumulator actual results to predicted results
;
; Return:
; Z flag = 1 (BEQ branch) if same
; Z flag = 0 (BNE branch) if different
;
02ca : COMPARE
if chk_a = 1
02ca : a504 lda DA
02cc : c506 cmp AR
02ce : d006 bne C1
endif
if chk_n = 1
lda DNVZC ; [7] see text
eor NF
and #$80 ; mask off N flag
bne C1
endif
if chk_v = 1
lda DNVZC ; [8] see text
eor VF
and #$40 ; mask off V flag
bne C1 ; [9] see text
endif
if chk_z = 1
lda DNVZC
eor ZF ; mask off Z flag
and #2
bne C1 ; [10] see text
endif
if chk_c = 1
02d0 : a505 lda DNVZC
02d2 : 450a eor CF
02d4 : 2901 and #1 ; mask off C flag
endif
02d6 : 60 C1 rts
; These routines store the predicted values for ADC and SBC for the 6502,
; 65C02, and 65816 in AR, CF, NF, VF, and ZF
if cputype = 0
A6502 lda VF ; 6502
;
; since all 8 bits of the P register were stored in VF, bit 7 of VF contains
; the N flag for NF
;
sta NF
lda HNVZC
sta ZF
rts
S6502 jsr SUB1
lda HNVZC
sta NF
sta VF
sta ZF
sta CF
rts
endif
if cputype = 1
02d7 : a506 A6502 lda AR ; 65C02
02d9 : 08 php
02da : 68 pla
02db : 8507 sta NF
02dd : 8509 sta ZF
02df : 60 rts
02e0 : 20ab02 S6502 jsr SUB2
02e3 : a506 lda AR
02e5 : 08 php
02e6 : 68 pla
02e7 : 8507 sta NF
02e9 : 8509 sta ZF
02eb : a503 lda HNVZC
02ed : 8508 sta VF
02ef : 850a sta CF
02f1 : 60 rts
endif
if cputype = 2
A6502 lda AR ; 65C816
php
pla
sta NF
sta ZF
rts
S6502 jsr SUB1
lda AR
php
pla
sta NF
sta ZF
lda HNVZC
sta VF
sta CF
rts
endif
02e0 = end TEST
No errors in pass 2.
Wrote binary from address $0200 through $02f1.
Total size 242 bytes.
Program start address is at $0200 (512).

View File

@ -10,14 +10,18 @@ The 6502_interrupt_test.a65 is a simple test to check the interrupt system
of both processors. A feedback register is required to inject IRQ and NMI
requests.
The 6502_decimal_test.a65 is Bruce Clark's code to accurately test decimal mode
of the various 6502 cores (6502, 65c02 & 65816 in 8-bit mode) with added
configuration options (invalid bcd or not, which flags to ignore).
Detailed information about how to configure, assemble and run the tests is
included in each source file.
The tests have primarily been written to test my own ATMega16 6502 emulator
project. You can find it here: http://2m5.de/6502_Emu/index.htm
The assembler used is no longer available on the author's website. as65_142.zip
is now included in this repository.
A discussion about the tests can be found here:
http://forum.6502.org/viewtopic.php?f=2&t=2241
And no, I will not switch to another assembler. However, GitHub user amb5l has
a CA65 compatible version in his repository.
Good luck debugging your emulator, simulator, fpga core, discrete
logic implementation or whatever you have!

View File

@ -0,0 +1,426 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)adca"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
next lda pb
and #%00001000
bne decmode
lda db
sta da
sta dr
sta cmd0+1
and #$7f
sta cmd1+1
clc
lda pb
and #1
beq noc
sec
noc php
lda ab
cmd0 adc #0
sta ar
lda pb
ora #%00110000
and #%00111100
bcc noc1
ora #1
noc1 tax
lda ab
and #$7f
plp
cmd1 adc #0
bmi neg
txa
and #1
beq cont
set txa
ora #%01000000
tax
jmp cont
neg txa
and #1
beq set
cont lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
jmp deccont
decmode
.block
lda db
sta da
sta dr
and #$0f
sta l0+1
lda pb
ora #%00110000
and #%00111100
tax
lda pb
lsr a
lda ab
and #$0f
l0 adc #0
ldy #$00
cmp #$0a
bcc l1
sec
sbc #$0a
and #$0f
ldy #$08
l1 sta ar
sty l2+1
sty l3+1
lda db
and #$f0
ora l3+1
sta l3+1
lda ab
and #$f0
l2 ora #0
clc
l3 adc #0
php
bcs l4
cmp #$a0
bcc l5
l4 sec
sbc #$a0
inx
l5 ora ar
sta ar
plp
bvc nov
php
txa
ora #%01000000
tax
plp
nov bpl non
txa
ora #%10000000
tax
non lda pb
lsr a
lda ab
adc db
bne noz
txa
ora #%00000010
tax
noz stx pr
.bend
deccont lda xb
sta xr
lda yb
sta yr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd adc da
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "adcax"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,435 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)adcax"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
sta xb
next lda pb
and #%00001000
bne decmode
lda db
sta da
sta dr
sta cmd0+1
and #$7f
sta cmd1+1
clc
lda pb
and #1
beq noc
sec
noc php
lda ab
cmd0 adc #0
sta ar
lda pb
ora #%00110000
and #%00111100
bcc noc1
ora #1
noc1 tax
lda ab
and #$7f
plp
cmd1 adc #0
bmi neg
txa
and #1
beq cont
set txa
ora #%01000000
tax
jmp cont
neg txa
and #1
beq set
cont lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
jmp deccont
decmode
.block
lda db
sta da
sta dr
and #$0f
sta l0+1
lda pb
ora #%00110000
and #%00111100
tax
lda pb
lsr a
lda ab
and #$0f
l0 adc #0
ldy #$00
cmp #$0a
bcc l1
sec
sbc #$0a
and #$0f
ldy #$08
l1 sta ar
sty l2+1
sty l3+1
lda db
and #$f0
ora l3+1
sta l3+1
lda ab
and #$f0
l2 ora #0
clc
l3 adc #0
php
bcs l4
cmp #$a0
bcc l5
l4 sec
sbc #$a0
inx
l5 ora ar
sta ar
plp
bvc nov
php
txa
ora #%01000000
tax
plp
nov bpl non
txa
ora #%10000000
tax
non lda pb
lsr a
lda ab
adc db
bne noz
txa
ora #%00000010
tax
noz stx pr
.bend
deccont lda xb
sta xr
lda yb
sta yr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd adc da,x
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
inc cmd+1
bne noinc
inc cmd+2
noinc lda xb
bne nodec
dec cmd+2
nodec dec xb
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "adcay"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,435 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)adcay"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
sta yb
next lda pb
and #%00001000
bne decmode
lda db
sta da
sta dr
sta cmd0+1
and #$7f
sta cmd1+1
clc
lda pb
and #1
beq noc
sec
noc php
lda ab
cmd0 adc #0
sta ar
lda pb
ora #%00110000
and #%00111100
bcc noc1
ora #1
noc1 tax
lda ab
and #$7f
plp
cmd1 adc #0
bmi neg
txa
and #1
beq cont
set txa
ora #%01000000
tax
jmp cont
neg txa
and #1
beq set
cont lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
jmp deccont
decmode
.block
lda db
sta da
sta dr
and #$0f
sta l0+1
lda pb
ora #%00110000
and #%00111100
tax
lda pb
lsr a
lda ab
and #$0f
l0 adc #0
ldy #$00
cmp #$0a
bcc l1
sec
sbc #$0a
and #$0f
ldy #$08
l1 sta ar
sty l2+1
sty l3+1
lda db
and #$f0
ora l3+1
sta l3+1
lda ab
and #$f0
l2 ora #0
clc
l3 adc #0
php
bcs l4
cmp #$a0
bcc l5
l4 sec
sbc #$a0
inx
l5 ora ar
sta ar
plp
bvc nov
php
txa
ora #%01000000
tax
plp
nov bpl non
txa
ora #%10000000
tax
non lda pb
lsr a
lda ab
adc db
bne noz
txa
ora #%00000010
tax
noz stx pr
.bend
deccont lda xb
sta xr
lda yb
sta yr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd adc da,y
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
inc cmd+1
bne noinc
inc cmd+2
noinc lda yb
bne nodec
dec cmd+2
nodec dec yb
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "adcix"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,428 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)adcb"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
next lda pb
and #%00001000
bne decmode
lda db
sta da
sta dr
sta cmd+1
sta cmd0+1
and #$7f
sta cmd1+1
clc
lda pb
and #1
beq noc
sec
noc php
lda ab
cmd0 adc #0
sta ar
lda pb
ora #%00110000
and #%00111100
bcc noc1
ora #1
noc1 tax
lda ab
and #$7f
plp
cmd1 adc #0
bmi neg
txa
and #1
beq cont
set txa
ora #%01000000
tax
jmp cont
neg txa
and #1
beq set
cont lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
jmp deccont
decmode
.block
lda db
sta da
sta dr
sta cmd+1
and #$0f
sta l0+1
lda pb
ora #%00110000
and #%00111100
tax
lda pb
lsr a
lda ab
and #$0f
l0 adc #0
ldy #$00
cmp #$0a
bcc l1
sec
sbc #$0a
and #$0f
ldy #$08
l1 sta ar
sty l2+1
sty l3+1
lda db
and #$f0
ora l3+1
sta l3+1
lda ab
and #$f0
l2 ora #0
clc
l3 adc #0
php
bcs l4
cmp #$a0
bcc l5
l4 sec
sbc #$a0
inx
l5 ora ar
sta ar
plp
bvc nov
php
txa
ora #%01000000
tax
plp
nov bpl non
txa
ora #%10000000
tax
non lda pb
lsr a
lda ab
adc db
bne noz
txa
ora #%00000010
tax
noz stx pr
.bend
deccont lda xb
sta xr
lda yb
sta yr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd adc #0
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "adcz"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,434 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)adcix"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
sta xb
lda #<da
sta 172
lda #>da
sta 173
next lda pb
and #%00001000
bne decmode
lda db
sta da
sta dr
sta cmd0+1
and #$7f
sta cmd1+1
clc
lda pb
and #1
beq noc
sec
noc php
lda ab
cmd0 adc #0
sta ar
lda pb
ora #%00110000
and #%00111100
bcc noc1
ora #1
noc1 tax
lda ab
and #$7f
plp
cmd1 adc #0
bmi neg
txa
and #1
beq cont
set txa
ora #%01000000
tax
jmp cont
neg txa
and #1
beq set
cont lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
jmp deccont
decmode
.block
lda db
sta da
sta dr
and #$0f
sta l0+1
lda pb
ora #%00110000
and #%00111100
tax
lda pb
lsr a
lda ab
and #$0f
l0 adc #0
ldy #$00
cmp #$0a
bcc l1
sec
sbc #$0a
and #$0f
ldy #$08
l1 sta ar
sty l2+1
sty l3+1
lda db
and #$f0
ora l3+1
sta l3+1
lda ab
and #$f0
l2 ora #0
clc
l3 adc #0
php
bcs l4
cmp #$a0
bcc l5
l4 sec
sbc #$a0
inx
l5 ora ar
sta ar
plp
bvc nov
php
txa
ora #%01000000
tax
plp
nov bpl non
txa
ora #%10000000
tax
non lda pb
lsr a
lda ab
adc db
bne noz
txa
ora #%00000010
tax
noz stx pr
.bend
deccont lda xb
sta xr
lda yb
sta yr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd adc (172,x)
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
inc cmd+1
dec xb
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "adciy"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,439 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)adciy"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
sta yb
lda #<da
sta 172
lda #>da
sta 173
next lda pb
and #%00001000
bne decmode
lda db
sta da
sta dr
sta cmd0+1
and #$7f
sta cmd1+1
clc
lda pb
and #1
beq noc
sec
noc php
lda ab
cmd0 adc #0
sta ar
lda pb
ora #%00110000
and #%00111100
bcc noc1
ora #1
noc1 tax
lda ab
and #$7f
plp
cmd1 adc #0
bmi neg
txa
and #1
beq cont
set txa
ora #%01000000
tax
jmp cont
neg txa
and #1
beq set
cont lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
jmp deccont
decmode
.block
lda db
sta da
sta dr
and #$0f
sta l0+1
lda pb
ora #%00110000
and #%00111100
tax
lda pb
lsr a
lda ab
and #$0f
l0 adc #0
ldy #$00
cmp #$0a
bcc l1
sec
sbc #$0a
and #$0f
ldy #$08
l1 sta ar
sty l2+1
sty l3+1
lda db
and #$f0
ora l3+1
sta l3+1
lda ab
and #$f0
l2 ora #0
clc
l3 adc #0
php
bcs l4
cmp #$a0
bcc l5
l4 sec
sbc #$a0
inx
l5 ora ar
sta ar
plp
bvc nov
php
txa
ora #%01000000
tax
plp
nov bpl non
txa
ora #%10000000
tax
non lda pb
lsr a
lda ab
adc db
bne noz
txa
ora #%00000010
tax
noz stx pr
.bend
deccont lda xb
sta xr
lda yb
sta yr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd adc (172),y
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
inc 172
bne noinc
inc 173
noinc lda yb
bne nodec
dec 173
nodec dec yb
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "sbcb"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,428 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)adcz"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
next lda pb
and #%00001000
bne decmode
lda db
sta 172
sta dr
sta cmd0+1
and #$7f
sta cmd1+1
clc
lda pb
and #1
beq noc
sec
noc php
lda ab
cmd0 adc #0
sta ar
lda pb
ora #%00110000
and #%00111100
bcc noc1
ora #1
noc1 tax
lda ab
and #$7f
plp
cmd1 adc #0
bmi neg
txa
and #1
beq cont
set txa
ora #%01000000
tax
jmp cont
neg txa
and #1
beq set
cont lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
jmp deccont
decmode
.block
lda db
sta 172
sta dr
and #$0f
sta l0+1
lda pb
ora #%00110000
and #%00111100
tax
lda pb
lsr a
lda ab
and #$0f
l0 adc #0
ldy #$00
cmp #$0a
bcc l1
sec
sbc #$0a
and #$0f
ldy #$08
l1 sta ar
sty l2+1
sty l3+1
lda db
and #$f0
ora l3+1
sta l3+1
lda ab
and #$f0
l2 ora #0
clc
l3 adc #0
php
bcs l4
cmp #$a0
bcc l5
l4 sec
sbc #$a0
inx
l5 ora ar
sta ar
plp
bvc nov
php
txa
ora #%01000000
tax
plp
nov bpl non
txa
ora #%10000000
tax
non lda pb
lsr a
lda ab
adc db
bne noz
txa
ora #%00000010
tax
noz stx pr
.bend
deccont lda xb
sta xr
lda yb
sta yr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd adc 172
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
lda 172
sta da
jsr check
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "adczx"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,432 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)adczx"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
sta xb
next lda pb
and #%00001000
bne decmode
lda db
sta 172
sta dr
sta cmd0+1
and #$7f
sta cmd1+1
clc
lda pb
and #1
beq noc
sec
noc php
lda ab
cmd0 adc #0
sta ar
lda pb
ora #%00110000
and #%00111100
bcc noc1
ora #1
noc1 tax
lda ab
and #$7f
plp
cmd1 adc #0
bmi neg
txa
and #1
beq cont
set txa
ora #%01000000
tax
jmp cont
neg txa
and #1
beq set
cont lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
jmp deccont
decmode
.block
lda db
sta 172
sta dr
and #$0f
sta l0+1
lda pb
ora #%00110000
and #%00111100
tax
lda pb
lsr a
lda ab
and #$0f
l0 adc #0
ldy #$00
cmp #$0a
bcc l1
sec
sbc #$0a
and #$0f
ldy #$08
l1 sta ar
sty l2+1
sty l3+1
lda db
and #$f0
ora l3+1
sta l3+1
lda ab
and #$f0
l2 ora #0
clc
l3 adc #0
php
bcs l4
cmp #$a0
bcc l5
l4 sec
sbc #$a0
inx
l5 ora ar
sta ar
plp
bvc nov
php
txa
ora #%01000000
tax
plp
nov bpl non
txa
ora #%10000000
tax
non lda pb
lsr a
lda ab
adc db
bne noz
txa
ora #%00000010
tax
noz stx pr
.bend
deccont lda xb
sta xr
lda yb
sta yr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd adc 172,x
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
lda 172
sta da
jsr check
inc cmd+1
dec xb
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "adca"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,327 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)alrb"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
next lda db
sta da
sta dr
sta cmd+1
lda pb
pha
plp
lda ab
and db
lsr a
sta ar
php
pla
sta pr
lda xb
sta xr
lda yb
sta yr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd .byte $4b
.byte 0
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "arrb"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,346 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)ancb"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
lda #$0b
sta cmd
next lda db
sta da
sta dr
sta cmd+1
eor #$ff
sta cmdr+1
lda ab
eor #$ff
cmdr ora #0
eor #$ff
sta ar
lda xb
sta xr
lda yb
sta yr
lda pb
ora #%00110000
and #%01111100
tax
lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000001
tax
noneg stx pr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd .byte 0
.byte 0
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
lda #$2b
cmp cmd
beq end
sta cmd
jmp next
end
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "lasay"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,336 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)anda"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
next lda db
sta da
sta dr
eor #$ff
sta cmdr+1
lda ab
eor #$ff
cmdr ora #0
eor #$ff
sta ar
lda xb
sta xr
lda yb
sta yr
lda pb
ora #%00110000
and #%01111101
tax
lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd and da
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "andax"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,345 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)andax"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
sta xb
next lda db
sta da
sta dr
eor #$ff
sta cmdr+1
lda ab
eor #$ff
cmdr ora #0
eor #$ff
sta ar
lda xb
sta xr
lda yb
sta yr
lda pb
ora #%00110000
and #%01111101
tax
lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd and da,x
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
inc cmd+1
bne noinc
inc cmd+2
noinc lda xb
bne nodec
dec cmd+2
nodec dec xb
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "anday"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,345 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)anday"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
sta yb
next lda db
sta da
sta dr
eor #$ff
sta cmdr+1
lda ab
eor #$ff
cmdr ora #0
eor #$ff
sta ar
lda xb
sta xr
lda yb
sta yr
lda pb
ora #%00110000
and #%01111101
tax
lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd and da,y
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
inc cmd+1
bne noinc
inc cmd+2
noinc lda yb
bne nodec
dec cmd+2
nodec dec yb
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "andix"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,337 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)andb"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
next lda db
sta da
sta dr
sta cmd+1
eor #$ff
sta cmdr+1
lda ab
eor #$ff
cmdr ora #0
eor #$ff
sta ar
lda xb
sta xr
lda yb
sta yr
lda pb
ora #%00110000
and #%01111101
tax
lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd and #0
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "andz"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,344 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)andix"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
sta xb
lda #<da
sta 172
lda #>da
sta 173
next lda db
sta da
sta dr
eor #$ff
sta cmdr+1
lda ab
eor #$ff
cmdr ora #0
eor #$ff
sta ar
lda xb
sta xr
lda yb
sta yr
lda pb
ora #%00110000
and #%01111101
tax
lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd and (172,x)
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
inc cmd+1
dec xb
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "andiy"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,349 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)andiy"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
sta yb
lda #<da
sta 172
lda #>da
sta 173
next lda db
sta da
sta dr
eor #$ff
sta cmdr+1
lda ab
eor #$ff
cmdr ora #0
eor #$ff
sta ar
lda xb
sta xr
lda yb
sta yr
lda pb
ora #%00110000
and #%01111101
tax
lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd and (172),y
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
inc 172
bne noinc
inc 173
noinc lda yb
bne nodec
dec 173
nodec dec yb
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "orab"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,338 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)andz"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
next lda db
sta 172
sta dr
eor #$ff
sta cmdr+1
lda ab
eor #$ff
cmdr ora #0
eor #$ff
sta ar
lda xb
sta xr
lda yb
sta yr
lda pb
ora #%00110000
and #%01111101
tax
lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd and 172
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
lda 172
sta da
jsr check
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "andzx"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,342 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)andzx"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
sta xb
next lda db
sta 172
sta dr
eor #$ff
sta cmdr+1
lda ab
eor #$ff
cmdr ora #0
eor #$ff
sta ar
lda xb
sta xr
lda yb
sta yr
lda pb
ora #%00110000
and #%01111101
tax
lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
nozero lda ar
bpl noneg
txa
ora #%10000000
tax
noneg stx pr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd and 172,x
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
lda 172
sta da
jsr check
inc cmd+1
dec xb
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "anda"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,341 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)aneb"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta xb
next lda db
sta da
sta dr
sta cmd+1
lda ab
ora #$ee
and xb
and db
sta ar
lda xb
sta xr
lda yb
sta yr
lda pb
ora #%00110000
and #%01111101
ldx ar
bne nozero
ora #%00000010
nozero
ldx ar
bpl nominus
ora #%10000000
nominus
sta pr
lda sb
sta sr
waitborder
lda $d011
bmi border
lda $d012
cmp #40
bcs waitborder
border
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd .byte $8b
.byte 0
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
inc ab
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda xb
adc #17
sta xb
bcc jmpnext
lda #0
sta xb
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "lxab"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,409 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)arrb"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta ab
next lda db
sta da
sta dr
sta cmd+1
lda #%00001000
bit pb
bne decimal
lda pb
lsr a
lda ab
and db
ror a
sta ar
lda pb
ora #%00110000
and #%00111100
ldx ar
bne nozero
ora #%00000010
nozero
ldx ar
bpl nominus
ora #%10000000
nominus
tax
lda ar
and #%01000000
beq nocarry
inx
nocarry
lda ar
and #%01100000
beq noover
cmp #%01100000
beq noover
txa
ora #%01000000
tax
noover
stx pr
jmp nodecimal
decimal
lda pb
lsr a
lda ab
and db
sta aa
ror a
sta ar
lda pb
ora #%00110000
and #%00111100
ldx ar
bne dnozero
ora #%00000010
dnozero
ldx ar
bpl dnominus
ora #%10000000
dnominus
tax
lda ar
eor aa
and #%01000000
beq dnoover
txa
ora #%01000000
tax
dnoover
lda aa
and #$0f
cmp #$05
bcc noadjustlow
lda ar
and #$f0
sta andlow+1
lda ar
clc
adc #$06
and #$0f
andlow ora #$11
sta ar
noadjustlow
lda aa
and #$f0
cmp #$50
bcc noadjusthigh
inx
lda ar
clc
adc #$60
sta ar
noadjusthigh
stx pr
nodecimal
lda xb
sta xr
lda yb
sta yr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd .byte $6b
.byte 0
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
clc
lda db
adc #17
sta db
bcc jmpnext
lda #0
sta db
clc
lda ab
adc #17
sta ab
bcc jmpnext
lda #0
sta ab
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "aneb"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,325 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)asla"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
next lda db
sta da
sta dr
asl dr
lda ab
sta ar
lda xb
sta xr
lda yb
sta yr
lda pb
ora #%00110000
and #%01111100
tax
lda dr
cmp #0
bne nozero
txa
ora #%00000010
tax
lda dr
nozero asl a
bcc noneg
txa
ora #%10000000
tax
noneg lda db
bpl nocarry
txa
ora #%00000001
tax
nocarry stx pr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd asl da
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
inc db
bne jmpnext
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "aslax"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,334 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)aslax"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta xb
next lda db
sta da
sta dr
asl dr
lda ab
sta ar
lda xb
sta xr
lda yb
sta yr
lda pb
ora #%00110000
and #%01111100
tax
lda dr
cmp #0
bne nozero
txa
ora #%00000010
tax
lda dr
nozero asl a
bcc noneg
txa
ora #%10000000
tax
noneg lda db
bpl nocarry
txa
ora #%00000001
tax
nocarry stx pr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd asl da,x
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
inc cmd+1
bne noinc
inc cmd+2
noinc lda xb
bne nodec
dec cmd+2
nodec dec xb
inc db
bne jmpnext
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "lsrn"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,326 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)asln"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta ab
next lda db
sta da
sta dr
lda ab
sta aa
sta ar
asl ar
lda xb
sta xr
lda yb
sta yr
lda pb
ora #%00110000
and #%01111100
tax
lda ar
cmp #0
bne nozero
txa
ora #%00000010
tax
lda ar
nozero asl a
bcc noneg
txa
ora #%10000000
tax
noneg lda ab
bpl nocarry
txa
ora #%00000001
tax
nocarry stx pr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd asl a
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
jsr check
inc ab
bne jmpnext
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "aslz"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,327 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)aslz"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
next lda db
sta 172
sta dr
asl dr
lda ab
sta ar
lda xb
sta xr
lda yb
sta yr
lda pb
ora #%00110000
and #%01111100
tax
lda dr
cmp #0
bne nozero
txa
ora #%00000010
tax
lda dr
nozero asl a
bcc noneg
txa
ora #%10000000
tax
noneg lda db
bpl nocarry
txa
ora #%00000001
tax
nocarry stx pr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd asl 172
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
lda 172
sta da
jsr check
inc db
bne jmpnext
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "aslzx"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

View File

@ -0,0 +1,331 @@
*= $0801
.byte $4c,$16,$08,$00,$97,$32
.byte $2c,$30,$3a,$9e,$32,$30
.byte $37,$30,$00,$00,$00,$a9
.byte $01,$85,$02
jsr print
.byte 13
.text "(up)aslzx"
.byte 0
lda #%00011011
sta db
lda #%11000110
sta ab
lda #%10110001
sta xb
lda #%01101100
sta yb
lda #0
sta pb
tsx
stx sb
lda #0
sta db
sta xb
next lda db
sta 172
sta dr
asl dr
lda ab
sta ar
lda xb
sta xr
lda yb
sta yr
lda pb
ora #%00110000
and #%01111100
tax
lda dr
cmp #0
bne nozero
txa
ora #%00000010
tax
lda dr
nozero asl a
bcc noneg
txa
ora #%10000000
tax
noneg lda db
bpl nocarry
txa
ora #%00000001
tax
nocarry stx pr
lda sb
sta sr
ldx sb
txs
lda pb
pha
lda ab
ldx xb
ldy yb
plp
cmd asl 172,x
php
cld
sta aa
stx xa
sty ya
pla
sta pa
tsx
stx sa
lda 172
sta da
jsr check
inc cmd+1
dec xb
inc db
bne jmpnext
inc pb
beq nonext
jmpnext jmp next
nonext
jsr print
.text " - ok"
.byte 13,0
lda 2
beq load
wait jsr $ffe4
beq wait
jmp $8000
load jsr print
name .text "asla"
namelen = *-name
.byte 0
lda #0
sta $0a
sta $b9
lda #namelen
sta $b7
lda #<name
sta $bb
lda #>name
sta $bc
pla
pla
jmp $e16f
db .byte 0
ab .byte 0
xb .byte 0
yb .byte 0
pb .byte 0
sb .byte 0
da .byte 0
aa .byte 0
xa .byte 0
ya .byte 0
pa .byte 0
sa .byte 0
dr .byte 0
ar .byte 0
xr .byte 0
yr .byte 0
pr .byte 0
sr .byte 0
check
.block
lda da
cmp dr
bne error
lda aa
cmp ar
bne error
lda xa
cmp xr
bne error
lda ya
cmp yr
bne error
lda pa
cmp pr
bne error
lda sa
cmp sr
bne error
rts
error jsr print
.byte 13
.null "before "
ldx #<db
ldy #>db
jsr showregs
jsr print
.byte 13
.null "after "
ldx #<da
ldy #>da
jsr showregs
jsr print
.byte 13
.null "right "
ldx #<dr
ldy #>dr
jsr showregs
lda #13
jsr $ffd2
wait jsr $ffe4
beq wait
cmp #3
beq stop
rts
stop lda 2
beq basic
jmp $8000
basic jmp ($a002)
showregs stx 172
sty 173
ldy #0
lda (172),y
jsr hexb
lda #32
jsr $ffd2
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
jsr hexb
lda #32
jsr $ffd2
iny
lda (172),y
ldx #"n"
asl a
bcc ok7
ldx #"N"
ok7 pha
txa
jsr $ffd2
pla
ldx #"v"
asl a
bcc ok6
ldx #"V"
ok6 pha
txa
jsr $ffd2
pla
ldx #"0"
asl a
bcc ok5
ldx #"1"
ok5 pha
txa
jsr $ffd2
pla
ldx #"b"
asl a
bcc ok4
ldx #"B"
ok4 pha
txa
jsr $ffd2
pla
ldx #"d"
asl a
bcc ok3
ldx #"D"
ok3 pha
txa
jsr $ffd2
pla
ldx #"i"
asl a
bcc ok2
ldx #"I"
ok2 pha
txa
jsr $ffd2
pla
ldx #"z"
asl a
bcc ok1
ldx #"Z"
ok1 pha
txa
jsr $ffd2
pla
ldx #"c"
asl a
bcc ok0
ldx #"C"
ok0 pha
txa
jsr $ffd2
pla
lda #32
jsr $ffd2
iny
lda (172),y
.bend
hexb pha
lsr a
lsr a
lsr a
lsr a
jsr hexn
pla
and #$0f
hexn ora #$30
cmp #$3a
bcc hexn0
adc #6
hexn0 jmp $ffd2
print pla
.block
sta print0+1
pla
sta print0+2
ldx #1
print0 lda !*,x
beq print1
jsr $ffd2
inx
bne print0
print1 sec
txa
adc print0+1
sta print2+1
lda #0
adc print0+2
sta print2+2
print2 jmp !*
.bend

Some files were not shown because too many files have changed in this diff Show More