├── .gitignore ├── Arduino ├── ROMIMAGE.bin ├── make_header.sh └── arduino_6502_mouse │ ├── arduino_6502_mouse.ino │ └── cpu.c ├── M-OS-6502 ├── MOUSE_ROM.bin ├── MOUSE_ROM.dsk ├── make.sh ├── README.md ├── MIOS_kernel_jmptable.asm ├── MIOS_macros.asm ├── MOS_main.asm ├── MIOS_driver_ACIApy65mon.asm ├── MIOS_defines.asm ├── MIOS_kernel.asm ├── MOS_monitor.asm ├── SW_chess.asm ├── SW_disassembler.asm ├── SW_vtl2a.asm └── labelmap.txt ├── Documents ├── Quickstart-German.odt └── Quickstart-German.pdf ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Scratch/* 3 | -------------------------------------------------------------------------------- /Arduino/ROMIMAGE.bin: -------------------------------------------------------------------------------- 1 | ../M-OS-6502/MOUSE_ROM.bin -------------------------------------------------------------------------------- /M-OS-6502/MOUSE_ROM.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkeller0815/MOUSE2Go/HEAD/M-OS-6502/MOUSE_ROM.bin -------------------------------------------------------------------------------- /M-OS-6502/MOUSE_ROM.dsk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkeller0815/MOUSE2Go/HEAD/M-OS-6502/MOUSE_ROM.dsk -------------------------------------------------------------------------------- /Documents/Quickstart-German.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkeller0815/MOUSE2Go/HEAD/Documents/Quickstart-German.odt -------------------------------------------------------------------------------- /Documents/Quickstart-German.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkeller0815/MOUSE2Go/HEAD/Documents/Quickstart-German.pdf -------------------------------------------------------------------------------- /M-OS-6502/make.sh: -------------------------------------------------------------------------------- 1 | export PYTHONPATH=/usr/local/lib/python2.7/site-packages/ 2 | 3 | ophis -l listfile.txt -m labelmap.txt -o MOUSE_ROM.bin MOS_main.asm 4 | #py65mon -m 65c02 -r ophis.bin 5 | 6 | -------------------------------------------------------------------------------- /Arduino/make_header.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # create C-Header out of the binary image 4 | xxd -i ROMIMAGE.bin > arduino_6502_mouse/rom_image.h 5 | 6 | 7 | # now adjust the declartion part 8 | sed -i '' 's/unsigned char ROMIMAGE_bin\[\] =/const uchar BIOS\[8192\] PROGMEM =/g' arduino_6502_mouse/rom_image.h 9 | 10 | -------------------------------------------------------------------------------- /M-OS-6502/README.md: -------------------------------------------------------------------------------- 1 | # M-OS initial version 2 | 3 | this is a minimalistic OS for MOUSE. 4 | 5 | 6 | 7 | ## Files: 8 | * MIOS_defines.asm 9 | * MIOS_driver_ACIA6850.asm 10 | * MIOS_kernel.asm 11 | * MIOS_kernel_jmptable.asm 12 | * MIOS_macros.asm 13 | * MOS_main.asm 14 | * MOS_monitor.asm 15 | * MOUSE_ROM.bin 16 | * README.md 17 | * SW_chess.asm 18 | * SW_disassembler.asm 19 | * SW_vtl2a.asm 20 | * make.sh 21 | 22 | 23 | -------------------------------------------------------------------------------- /M-OS-6502/MIOS_kernel_jmptable.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; M-OS kernel for a minimal system 3 | ; 4 | ; 5 | 6 | 7 | ; 8 | ; JUMP Table for several kernel routines 9 | ; 10 | ; called with JSR 11 | ; 12 | ; this table should be located at the beginning of the ROM image 13 | ; to provide reliable addresses for internal functions even if the 14 | ; real start addresses of the routines move to different locations 15 | ; during development 16 | ; 17 | ; In software not directly bundled with the ROM image only these 18 | ; addresses should be used to access this functions. 19 | ; 20 | ; 21 | 22 | j_wstr: jmp k_wstr 23 | j_wchr: jmp k_wchr 24 | j_rchr: jmp k_rchr 25 | j_a2b: jmp k_ascii2byte 26 | j_bin8out: jmp u_bin8out 27 | j_hex8out: jmp u_hex8out 28 | j_hex4out: jmp u_hex4out 29 | j_chr2nibble: jmp u_chr2nibble 30 | 31 | ;k_RESET 32 | ;k_NMI 33 | ;k_IRQ 34 | -------------------------------------------------------------------------------- /M-OS-6502/MIOS_macros.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; MACROs for common tasks and repeating parts of code 3 | ; 4 | ; 5 | ; 6 | ; 7 | 8 | ; ----------------------------------------------------------------------------- 9 | ; MACRO for writing a line. Use with ".invoke print
" where 10 | ;
is the first byte of the string in 16 bit. As a "write" 11 | ; command, the string has to be terminated by a zero-byte ('\0') 12 | .macro print 13 | lda #<_1 14 | sta K_STRING_L 15 | lda #>_1 16 | sta K_STRING_H 17 | jsr j_wstr 18 | .macend 19 | 20 | ; ----------------------------------------------------------------------------- 21 | ; MACRO for writing a linefeed. Use with ".invoke linefeed" 22 | .macro linefeed 23 | lda #LINE_END 24 | jsr j_wchr 25 | .macend 26 | 27 | 28 | ; ----------------------------------------------------------------------------- 29 | ; MACRO for writing a space. Use with ".invoke space" 30 | .macro space 31 | lda #32 32 | jsr j_wchr 33 | .macend 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Mario Keller 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /M-OS-6502/MOS_main.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; M-OS 3 | ; 4 | ; Mouse-OS main file 5 | ; 6 | ; the ROM image is always built from this main file 7 | ; 8 | 9 | ; 10 | ; first define the macros used in the code 11 | ; 12 | .require "MIOS_macros.asm" 13 | 14 | ; 15 | ; load the defines for memory locations 16 | ; 17 | .require "MIOS_defines.asm" 18 | 19 | 20 | ; 21 | ; define the start-address of the tool that should be startet by the 22 | ; kernel after reset und k_START 23 | ; 24 | .alias MOUSESTART m_start ; define the monitor programm as start entry 25 | 26 | ; 27 | ; set the assembler to the start-address of the ROM image 28 | ; 29 | .org ROM_START 30 | 31 | ; 32 | ; the jumptable should always be the first part after ROM start 33 | ; 34 | .require "MIOS_kernel_jmptable.asm" 35 | 36 | ; 37 | ; include all other parts of the system 38 | ; 39 | 40 | .require "MOS_monitor.asm" 41 | .require "SW_vtl2a.asm" 42 | .require "SW_chess.asm" 43 | .require "SW_disassembler.asm" 44 | .require "SW_assembler.asm" 45 | 46 | 47 | ; 48 | ; the kernel is the last part, because it defines the RESET and IRQ 49 | ; vectors at the end of the file. 50 | ; 51 | .require "MIOS_kernel.asm" 52 | -------------------------------------------------------------------------------- /M-OS-6502/MIOS_driver_ACIApy65mon.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; DRIVER CODE FOR - Py65mon fake ACIA 3 | ; 4 | ; non blocking 5 | ; $F001 - putc - write character to console 6 | ; $F004 - getc - read character from console (0 if no character) 7 | 8 | ;.alias ACIAIN $F004 9 | .alias ACIAIN $FFF9 10 | ;.alias ACIAOUT $F001 11 | .alias ACIAOUT $FFF8 12 | 13 | ; 14 | ; initialize the ACIA 15 | ; 16 | ; not needed for py65mon, but still here to match the driver interface pattern 17 | ; 18 | ; @return: -- 19 | .scope 20 | acia_init: 21 | rts ; finished 22 | .scend 23 | 24 | ; 25 | ; send byte (blocking) 26 | ; 27 | ; py65mon is always nonblocking, so we don't have to care for that 28 | ; 29 | ; @param A - the byte to sent 30 | ; 31 | ; @return - 32 | .scope 33 | acia_send_b: 34 | sta ACIAOUT 35 | rts ; return 36 | .scend 37 | 38 | 39 | ; 40 | ; send byte (nonblocking) 41 | ; 42 | ; send one byte without checking 43 | ; 44 | ; @param A - the byte to sent 45 | ; 46 | ; @return - 47 | .scope 48 | acia_send: 49 | sta ACIAOUT ; send byte 50 | rts ; return 51 | .scend 52 | 53 | 54 | ; 55 | ; test if ACIA is ready to send 56 | ; 57 | ; ATTENTION: content of A is detroyed by this function 58 | ; 59 | ; @param - 60 | ; 61 | ; @return - set Z flag if ACIA is not ready to send 62 | .scope 63 | acia_ready2send: 64 | lda #$02 ; set bit 1 65 | rts ; return 66 | .scend 67 | 68 | 69 | ; 70 | ; test if a byte was received 71 | ; 72 | ; ATTENTION: content of A is detroyed by this function 73 | ; 74 | ; @param - 75 | ; 76 | ; @return - set Z flag if no data was received 77 | .scope 78 | acia_received: 79 | lda #$ff ; test bit 0 80 | rts ; return 81 | .scend 82 | 83 | 84 | ; 85 | ; read byte (blocking) 86 | ; 87 | ; ATTENTION: content of A is detroyed by this function 88 | ; 89 | ; @param - 90 | ; 91 | ; @return A - return the bytes that was received 92 | .scope 93 | acia_receive_b: 94 | lda ACIAIN ; read byte 95 | beq acia_receive_b ; check if >0 96 | rts ; return 97 | .scend 98 | 99 | ; 100 | ; read byte (nonblocking) 101 | ; 102 | ; ATTENTION: content of A is detroyed by this function 103 | ; 104 | ; @param - 105 | ; 106 | ; @return A - return the bytes that was received 107 | .scope 108 | acia_receive: 109 | lda ACIAIN ; read byte 110 | rts ; return 111 | .scend 112 | -------------------------------------------------------------------------------- /Arduino/arduino_6502_mouse/arduino_6502_mouse.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * MOUSE2Go - an Arduino based 6502 computer 4 | * 5 | * Author: Mario Keller 6 | * 7 | * 8 | * 9 | */ 10 | 11 | #define UNDOCUMENTED 12 | 13 | // set this to a proper value for your Arduino 14 | //#define RAM_SIZE 1536 // Uno, mini or any other 328P 15 | #define RAM_SIZE 6144 //Mega 2560 16 | //#define RAM_SIZE 32768 //Due 17 | 18 | 19 | #define NMI_pin 3 20 | #define IRQ_pin 4 21 | #define RESET_pin 5 22 | #define INSTRUCTIONS_PER_LOOP 100 23 | 24 | //#define USE_TIMING 1 25 | //#define SHOW_SPEED 1 26 | 27 | uint8_t curkey = 0; 28 | unsigned long starttime, endtime, counttime; 29 | 30 | extern "C" { 31 | uint16_t getpc(); 32 | uint8_t getop(); 33 | void exec6502(int32_t tickcount); 34 | void reset6502(); 35 | void nmi6502(); 36 | void irq6502(); 37 | 38 | void serout(uint8_t val) { 39 | if (val == 10) { 40 | Serial.println(); 41 | } 42 | else { 43 | Serial.write(val); 44 | } 45 | } 46 | 47 | 48 | uint8_t getkey() { 49 | return(curkey); 50 | } 51 | 52 | void clearkey() { 53 | curkey = 0; 54 | } 55 | 56 | } 57 | 58 | void setup () { 59 | Serial.begin (9600); 60 | Serial.println(); 61 | 62 | //set the externes pins for NMI, IRQ and RESET 63 | pinMode(NMI_pin, INPUT_PULLUP); 64 | pinMode(IRQ_pin, INPUT_PULLUP); 65 | pinMode(RESET_pin, INPUT_PULLUP); 66 | counttime = 0; 67 | reset6502(); 68 | } 69 | 70 | void loop () { 71 | #ifdef SHOW_SPEED 72 | if(counttime == 0) starttime = millis(); 73 | counttime++; 74 | if(counttime == 100000 ) { 75 | endtime = millis() - starttime; 76 | float ips = ((counttime * INSTRUCTIONS_PER_LOOP) / endtime ) * 1000; 77 | Serial.print(ips); 78 | #ifdef USE_TIMING 79 | Serial.println(" cycles per second"); 80 | #else 81 | Serial.println(" instructions per second"); 82 | #endif 83 | counttime = 0; 84 | } 85 | #endif 86 | 87 | //internal pullup resistor is used for the input pins 88 | //making them LOW active like the original 6502 pins 89 | //handle NMI 90 | if(!digitalRead(NMI_pin) ) { 91 | while(!digitalRead(NMI_pin)) { delay(10); } 92 | nmi6502(); 93 | } 94 | //handle IRQ 95 | if(!digitalRead(IRQ_pin)) { 96 | while(!digitalRead(IRQ_pin)) { delay(10); } 97 | irq6502(); 98 | } 99 | 100 | 101 | //handle RESET 102 | if(!digitalRead(RESET_pin)) { 103 | while(!digitalRead(RESET_pin)) { delay(10); } 104 | reset6502(); 105 | } 106 | 107 | exec6502(INSTRUCTIONS_PER_LOOP); //if timing is enabled, this value is in 6502 clock ticks. otherwise, simply instruction count. 108 | 109 | if (Serial.available()) { 110 | curkey = Serial.read() & 0x7F; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /M-OS-6502/MIOS_defines.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; M-OS 3 | ; 4 | ; global defines 5 | ; 6 | ; 7 | ;The MIT License (MIT) 8 | ; 9 | ;Copyright (c) 2015 Mario Keller 10 | ; 11 | ;Permission is hereby granted, free of charge, to any person obtaining a copy 12 | ;of this software and associated documentation files (the "Software"), to deal 13 | ;in the Software without restriction, including without limitation the rights 14 | ;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | ;copies of the Software, and to permit persons to whom the Software is 16 | ;furnished to do so, subject to the following conditions: 17 | ; 18 | ;The above copyright notice and this permission notice shall be included in all 19 | ;copies or substantial portions of the Software. 20 | ; 21 | ;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | ;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | ;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | ;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | ;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | ;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | ;SOFTWARE. 28 | ; 29 | ; 30 | 31 | .alias ACIA_START $8000 ; start of ACIA registers 32 | ;.alias ACIA_MODE $16 ; 8N1, 28800 baud 33 | .alias ACIA_MODE $15 ; 8N1, 115200 baud 34 | 35 | .alias STACK_END $ff ; top stackpointer value 36 | 37 | .alias ROM_START $e000 ; start of kernel rom image 38 | 39 | .alias SOFT_NMI $7FFC ; soft NMI vector 40 | .alias SOFT_IRQ $7FFE ; soft IRQ vector 41 | 42 | ; 43 | ; Zero Page defines 44 | ; 45 | ; ZP addresses used by several functions of the I/O system and the kernel 46 | ; 47 | ; this is needed by k_wstr function 48 | .alias K_STRING_L $00 ; ZP highbyte of string output address 49 | .alias K_STRING_H $01 ; ZP lowbyte of string output address 50 | .alias K_VAR1_L $02 ; ZP common variable (16 bit) 51 | .alias K_VAR1_H $03 52 | .alias K_VAR2_L $04 ; ZP common variable (16 bit) 53 | .alias K_VAR2_H $05 54 | .alias K_VAR3_L $06 ; ZP common variable (16 bit) 55 | .alias K_VAR3_H $07 56 | .alias K_VAR4_L $08 ; ZP common variable (16 bit) 57 | .alias K_VAR4_H $09 58 | .alias K_TMP1 $0A ; ZP temp variable (8bit) 59 | .alias K_TMP2 $0B ; ZP temp variable (8bit) 60 | .alias K_TMP3 $0C ; ZP temp variable (8bit) 61 | .alias K_TMP4 $0D ; ZP temp variable (8bit) 62 | .alias K_TMP5 $0E ; ZP temp variable (8bit) 63 | 64 | 65 | ; kernel input buffer / reserved from $0F to $2F 66 | ; 67 | .alias K_BUF_P $0F ; ZP variable holding pointer to end of buffer 68 | .alias K_BUFFER $10 ; ZP start of 32 bytes kernel input buffer 69 | .alias K_BUF_LEN $20 ; max length of input buffer (this is not an address) 70 | 71 | ; generic defines 72 | 73 | .alias LINE_END $0A ; define end of line character 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MOUSE2Go - A 6502 computer emulated by an Arduino 2 | ================================================= 3 | 4 | ## Important note! 5 | 6 | This repository contains software that was not written by me. 7 | 8 | 9 | ## 1.0 About 10 | 11 | MOUSE is an 65C02 based singleboard homebrew computer that 12 | is freely available from another repo: [github - MOUSE] (https://github.com/mkeller0815/MOUSE) 13 | 14 | To make it easier to ge started with software, MOUSE can now run on a plain Arduino or compatible board. 15 | 16 | This project uses software kindly provided by others. 17 | 18 | - 6502 emulator for Arduino by Mike Chambers (http://forum.arduino.cc/index.php?topic=193216.0) 19 | - microchess by Peter Jennings (http://www.benlo.com/microchess/) 20 | - VTL2 ported to the 6502 by Mike Barry (http://6502.org/source/interpreters/vtl02.htm) 21 | - 65C02 assembler/disassembler by Jeff Tranter (https://github.com/jefftranter/6502/tree/master/asm) 22 | 23 | ## 1.1 Arduino Firmware 24 | 25 | This part is mainly the 6502 emulator running on the Arduino. The sources are located in the 26 | "Arduino" folder. The folder "arduino_6502_mouse" contains the whole sketch that can be opened directly 27 | by the Arduino IDE. 28 | 29 | There is also a shellscript that creates a C header file out of the MOUSE rom image and a symlink to 30 | this image itself. 31 | 32 | Note: Currently there's only a 6502 emulated, not an 65C02 33 | 34 | ## 1.2 MOUSE Software 35 | 36 | The folder "M-OS-6502" contains the 6502 part of this project. The software ist written in assembler and 37 | can be assembled with the ophis assembler (https://michaelcmartin.github.io/Ophis/) 38 | 39 | There's a small shellscript that runs the assembler with all needed options. 40 | 41 | Using the lastet version of py65mon (https://github.com/mnaberez/py65) you can run the generated rom image 42 | also on your local machine with 43 | 44 | py65mon -i fff9 -o fff8 -m 6502 -r MOUSE_ROM.bin 45 | 46 | ## 2.0 Wiring 47 | 48 | Currently there's no wiring needed. Everything runs in software 49 | 50 | ## 3.0 Get started 51 | 52 | To get started you only need to load the "Arduino/arduino_6502_mouse/arduino_6502_mouse.ino" sketch into 53 | the Arduino IDE and programm your Arduino. 54 | 55 | There's a "#define" for the emulated RAM size, that you can adjust to get more memory for the emulator if 56 | you have an Arduino with more memory (like a Mega2560 or a Due). 57 | 58 | After uploading your sketch, you can connect to the Arduino via a serial terminal (or the serial monitor from 59 | the IDE) with 9600,8N1 and play with MOUSE. 60 | 61 | ## 4.0 Commands 62 | 63 | If your're connected to the emulated system the following commands can be used: 64 | 65 | - a - start assembler at address 66 | - c - start microchess - runs microchess 67 | - d - disassemble from address 68 | - f : %val - fill memory with %val 69 | - g - jump to 70 | - h - this help 71 | - i - input input data to memory '.' ends the input 72 | - m %cols %rows - dump memory from address 73 | - o : - output memory range 74 | - r - jump to reset vector 75 | - s - show one byte as hex and binary 76 | - v - start VTL2 language 77 | - 16bit address, %xx - 8 bit value 78 | 79 | ## 5.0 Memory Map 80 | 81 | 0x0000 - 0x00ff Zeropage 82 | 0x0100 - 0x01ff Stack 83 | 0x0200 - 0x03ff input buffer used only by VTL2 84 | 0x0400 start of program memroy for VTL2 85 | 0x0200 - 0x7ffb free memory (upper limit depends on Arduino RAM settings) 86 | 0x7ffc - 0x7ffd 16 bit address used as NMI vector from MIOS kernel (writeable) 87 | 0x7ffe - 0x7fff 16 bit address used as IRQ vector from MIOS kernel (writeable) 88 | 0xe000 - 0xffff ROM 89 | 90 | ## 6.0 Special Addresses 91 | 92 | 0x7ffc - 0x7ffd 16 bit address used as NMI vector from MIOS kernel (writeable) 93 | 0x7ffe - 0x7fff 16 bit address used as IRQ vector from MIOS kernel (writeable) 94 | 95 | 0xfff8 fake ACIA input register 96 | 0xfff9 fake ACIA output register 97 | 98 | 0xfffa - 0xfffb 6502 NMI vector 99 | 0xfffc - 0xfffd 6502 RESET vector 100 | 0xfffe - 0xffff 6502 IRQ vector 101 | 102 | ## 7.0 Using interrupts 103 | 104 | The 6502 emulator also supports interrupts. The current setup uses 3 Arduino pins to create 105 | low active inputs for 106 | 107 | - NMI -> digital pin 3 108 | - IRQ -> digital pin 4 109 | - RESET -> digital pin 5 110 | 111 | These pins are set as input and pulled high by an internal pullup resistor. Connecting them to GND 112 | causes the emulator to recognize the input an call the corresponding function. 113 | 114 | The interrupt does nior accure immediately, because the input pins are only checked every X instructions / cycles. 115 | The number set for INSTRUCTIONS_PER_LOOP effects this setting as well as the USE_TIMING setting. 116 | 117 | The interrupt vectors are placed in the ROM part of the sytem and therefor they cannot be changed. But the 118 | M-OS has some internal interrupt functions that make an indirect jump using the memory locations 119 | 120 | 0x7ffc -> soft NMI vector 121 | 0x7ffe -> soft IRQ vector 122 | 123 | These vectors are set by the internal reset function to point to an RTI opcode in ROM. 124 | 125 | If an NMI occures the OS calls a JMP(0x7ffc), what causes an RTI if the vector was not changed before. 126 | If an IRQ occures the OS calls a JMP(0x7ffe), what causes an RTI if the vector was not changed before. 127 | 128 | The 4 bytes from 0x7ffc to 0x7fff are not part of the "normal" emulated RAM and so they can be read and written even 129 | if the emulated system has less memory then 32k. This is necessary because the Arduino Uno (ATmega 328) has only 2k of SRAM 130 | and even the Arduino Mega has only 8k of SRAM. 131 | 132 | To use you own interrupt functions just set the soft vectors to the starting address of your functions. Be aware that a reset just sets 133 | the addresses back to the RTI in ROM. 134 | 135 | The emulator respects the setting of the interrupt flag in the status register of the emulated 6502. If the bit is set the IRQ ist not 136 | executed. An NMI is always executed just as for the real 6502. 137 | 138 | -------------------------------------------------------------------------------- /M-OS-6502/MIOS_kernel.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; M-OS kernel for a minimal system 3 | ; 4 | ; providing high level function for input and output of data 5 | ; 6 | ; providing reset and interrupt routines and an base entry point 7 | ; to start after reset / power on 8 | ; 9 | ; this file should always be the last file in an ROM image, because it 10 | ; defines the NMI, IRQ and NMI vectors at the end moving the address 11 | ; counter to $FFFF 12 | 13 | 14 | ;load the 6850 ACIA driver 15 | ; 16 | ; ACIA driver is directly imported here, because this version of the kernel 17 | ; makes direct use of the low level function form the driver. 18 | ; 19 | ; low level function should not be used outside the kernel to provide 20 | ; compatibility for software to other hardware configurations 21 | ; 22 | ;.require "MIOS_driver_ACIA6850.asm" 23 | .require "MIOS_driver_ACIApy65mon.asm" 24 | 25 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 26 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 27 | 28 | ; 29 | ; k_START 30 | ; 31 | ; simple start point of the kerne after reset. 32 | ; 33 | .scope 34 | k_START: 35 | .invoke print k_welcome ; print welcome message 36 | jmp MOUSESTART ; start what ever is defined as start tool 37 | brk 38 | .scend 39 | 40 | 41 | 42 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 43 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 44 | 45 | 46 | ; 47 | ; general utility functions for converting data or generate output 48 | ; 49 | 50 | 51 | ; 52 | ; print out the 8bit value in A as binary code 53 | ; X,Y and A are destroyed 54 | ; 55 | .scope 56 | u_bin8out: 57 | ldx #$08 ; counter for 8 bit 58 | _loop: clc ; clear carry flag 59 | ldy #'0 60 | asl ; shift byte by one position 61 | bcc _p0 62 | iny 63 | _p0: pha ; save A 64 | tya ; 65 | jsr k_wchr 66 | pla ; get A back 67 | dex ; decrement counter 68 | bne _loop 69 | rts ; return 70 | .scend 71 | 72 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 73 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 74 | 75 | 76 | ; 77 | ; write content of A as hex 78 | ; 79 | ; @param A - number to write (A is destroyed) 80 | ; 81 | .scope 82 | u_hex8out: 83 | pha ; save A 84 | lsr ; get hi nibble 85 | lsr 86 | lsr 87 | lsr 88 | jsr u_hex4out ; print high nibble 89 | pla ; restore A 90 | jsr u_hex4out ; print low nibble 91 | rts ; return 92 | .scend 93 | 94 | 95 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 96 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 97 | 98 | ; 99 | ; print low-nibble of A as hex digit 100 | ; 101 | ; @param A containing number (A is destroyed) 102 | ; 103 | ; @ return - 104 | .scope 105 | ; HEX digits for printing hexnumbers 106 | u_hex4out: 107 | stx K_TMP2 ; save X 108 | and #$0f ; mask high nibble out 109 | tax ; set digit index 110 | lda u_hexdigit,x ; load digit 111 | jsr k_wchr ; print character 112 | ldx K_TMP2 ; restore X 113 | rts ; return 114 | .scend 115 | u_hexdigit: .byte "0123456789abcdef" 116 | 117 | 118 | 119 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 120 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 121 | 122 | ; 123 | ; convert a character in A to one nibble 124 | ; works only for '0-'9','A'-'F' and 'a'-'f' all other chracters may 125 | ; cause unexpected results 126 | ; 127 | ; @param A containing the character (will be destroyed) 128 | ; 129 | ; @return A containung the nibble value 130 | .scope 131 | u_chr2nibble: 132 | sec ; set carry bit 133 | sbc #$30 ; substract 48 ('0') 134 | cmp #$0a ; check if lower then 10 135 | bcc + ; carry is clear if value is lower 10 136 | sec 137 | sbc #$07 ; substract 7 ('a'-'f') 138 | cmp #$10 ; carry is clear if value is lower 16 139 | bcc + 140 | sec 141 | sbc #$20 ; substract 32 ('A' - 'F') 142 | * rts ; return, Accumulator contains the digit 143 | .scend 144 | 145 | 146 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 147 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 148 | 149 | ; 150 | ; k_wstr 151 | ; write string to output 152 | ; K_STRING_L and K_STRING_H have to hold the startaddress of the string 153 | ; max length of string: 255 characters. string must be terminated by \0 154 | ; 155 | ; Y,A - are perserved 156 | ; 157 | ; @param - K_STRING_L (memorylocation with the startaddress of the string) 158 | ; 159 | ; @return - 160 | .scope 161 | k_wstr: 162 | pha ; save A to stack 163 | tya 164 | pha ; save Y to stack 165 | ldy #$00 ; set index 166 | * lda (K_STRING_L),y ; load character 167 | beq + 168 | jsr k_wchr ; print character 169 | iny ; increment index 170 | jmp - ; next character 171 | * pla ; restore Y 172 | tay 173 | pla ; restore A 174 | rts 175 | .scend 176 | 177 | 178 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 179 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 180 | 181 | ; k_wchr 182 | ; write one character to output 183 | ; 184 | ; @param A - character to write 185 | ; 186 | ; @return - 187 | .scope 188 | k_wchr: 189 | ; deactivated for testing with py65 190 | jsr acia_send_b ; send charachter to ACIA and wait until it was sent 191 | rts ; return 192 | ; current workaround for py65 193 | ; sta $f001 194 | ; rts 195 | .scend 196 | 197 | 198 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 199 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 200 | 201 | 202 | ; k_rchr 203 | ; read one character from input 204 | ; this is nonblocking, C flag is set if no charachter was read 205 | ; 206 | ; @param - 207 | ; 208 | ; @return - A the received byte or "0" with C flag set if no byte was recieved. 209 | .scope 210 | k_rchr: 211 | ; deactivated for testing with py65 212 | ; sec ; set carry flag 213 | ; jsr acia_received ; check if data is available 214 | ; beq + ; return, leave Z flag set 215 | ; jsr acia_receive ; read the byte 216 | ; clc ; clear carry flag to indicate data 217 | ;* rts ; return 218 | ; current workaround for py65 219 | sec ; set carry 220 | jsr acia_receive ; read character 221 | beq + ; no character read 222 | clc ; clear carry if character read 223 | * rts ; return 224 | .scend 225 | 226 | 227 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 228 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 229 | 230 | 231 | k_ascii2byte: 232 | ; convert two ascii characters in the kernel buffer to 233 | ; one byte. blank characters are skipped 234 | ; X is modified and A is destroyed 235 | ; K_TMP1 is modified 236 | ; 237 | ; @param - X containing the offset in K_BUFFER 238 | ; 239 | ; @return - A containing the parsed byte 240 | ; @return - X pointing to the byte after the last parsed character 241 | .scope 242 | * lda K_BUFFER,x ; read fists character 243 | inx ; increase index 244 | cmp #$20 ; check for blank 245 | beq - ; read next character 246 | jsr u_chr2nibble ; convert to first nibble 247 | asl 248 | asl 249 | asl 250 | asl ; shift to high nibble 251 | sta K_TMP1 ; save high nibble 252 | lda K_BUFFER,x 253 | jsr u_chr2nibble ; convert next nibble 254 | ora K_TMP1 ; add high nibble 255 | inx ; set indext to byte after last character 256 | rts 257 | .scend 258 | 259 | 260 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 261 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 262 | 263 | 264 | ; 265 | ; RESET 266 | ; 267 | ; 268 | .scope 269 | k_RESET: 270 | sei ; prevent interupts 271 | cld ; set binary mode 272 | ldx #$ff ; last RAM address for stack 273 | txs ; set stackpointer 274 | 275 | lda #$00 ; clear zeropage 276 | * sta $0,x ; 277 | dex ; 278 | bne - 279 | 280 | lda #ACIA_MODE ; set serial mode and init ACIA 281 | jsr acia_init ; init ACIA 282 | 283 | ; set the soft interrupt vectors 284 | ; to RAM 285 | 286 | lda #k_NMI_END ; get high addressbyte from NMI rti 289 | sta SOFT_NMI+1 ; store at SOFT_NMI address 290 | 291 | lda #k_IRQ_END ; get high addressbyte from IRQ rti 294 | sta SOFT_IRQ+1 ; store at SOFT_IRQ address 295 | 296 | cli ; reenable interupts 297 | 298 | jmp k_START ; start kernel 299 | .scend 300 | 301 | 302 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 303 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 304 | 305 | ; 306 | ; NMI hook. use soft NMI vector in RAM to make it changeable during runtime 307 | ; a reset sets SOFT_NMI to teh address of k_NMI_END 308 | ; 309 | .scope 310 | k_NMI: 311 | JMP(SOFT_NMI) ; jump to the address of the "virtual" NMI vector 312 | k_NMI_END: 313 | rti 314 | .scend 315 | 316 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 317 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 318 | 319 | ; 320 | ; IRQ hook. use soft IRQ vector in RAM to make it changeable during runtime 321 | ; a reset sets SOFT_IRQ to teh address of k_IRQ_END 322 | ; 323 | .scope 324 | k_IRQ: 325 | JMP(SOFT_IRQ) ; jump to the address of the "virtual" IRQ vector 326 | k_IRQ_END: 327 | rti 328 | .scend 329 | 330 | 331 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 332 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 333 | 334 | 335 | ; 336 | ; DATA section 337 | ; 338 | ; 339 | ; 340 | 341 | k_welcome: .byte LINE_END,"MOUSE 65C02 micro computer (c) 2017",LINE_END,"M-OS V0.3",LINE_END,"READY.",LINE_END,0 342 | ; 343 | ; fill ROM to vector table 344 | ; 345 | 346 | .advance $fffa 347 | 348 | .word k_NMI ; NMI vector 349 | .word k_RESET ; RESET vector 350 | .word k_IRQ ; IRQ vector 351 | -------------------------------------------------------------------------------- /M-OS-6502/MOS_monitor.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; M-OS monitor programm 3 | ; 4 | 5 | ; Character set 6 | .alias AsciiCC $03 ; break (Control-C) ASCCI character 7 | .alias AsciiBS $08 ; backspace ASCII character 8 | .alias AsciiLF $0A ; line feed ASCII character 9 | .alias AsciiCR $0D ; carriage return ASCII character 10 | .alias AsciiSP $20 ; space ASCII character 11 | .alias AsciiDS $2D ; dash/minus ASCII character 12 | .alias AsciiDEL $7F ; DEL ASCII character 13 | 14 | 15 | ; 16 | ; M-OS monitor main loop 17 | ; 18 | .scope 19 | 20 | m_start: 21 | .invoke print MS_WELCOME ; print welcome 22 | m_main: ; monitor main loop 23 | jsr m_clear_buffer ; clear input buffer 24 | jsr m_show_prompt ; show initial prompt 25 | 26 | 27 | _wait: 28 | jsr j_rchr ; read character 29 | bcs _wait ; wait for character 30 | cmp #AsciiCR ; check if carriage return 31 | beq m_parse ; parse buffer 32 | cmp #AsciiLF ; check if line feed 33 | beq m_parse ; parse buffer 34 | jsr j_wchr ; local echo character 35 | ldx K_BUF_P ; load current bufferpointer 36 | sta K_BUFFER,x ; put character to buffer 37 | inx ; increment bufferpointer 38 | stx K_BUF_P ; save buffer pointer 39 | cpx #K_BUF_LEN ; check for end of buffer 40 | beq m_parse ; if end of buffer -> parse 41 | jmp _wait ; next character 42 | 43 | m_parse: 44 | ; code for parsing commands here 45 | ldx #$00 ; set index to 0 46 | lda K_BUFFER,x ; load first character 47 | * cmp m_cmd_list,x ; compare to current command 48 | beq m_cmdjmp ; command found 49 | inx ; increment index 50 | cpx m_cmd_num ; end of command list? 51 | bne - ; next command 52 | .invoke print MS_CMD_ERROR ; unknown command 53 | pha ; save A 54 | lda #$22 ; print " 55 | jsr j_wchr 56 | pla ; print command character 57 | jsr j_wchr 58 | lda #$22 59 | jsr j_wchr ; print " 60 | lda #$20 61 | jsr j_wchr 62 | jmp m_parse_end 63 | m_cmdjmp: 64 | .invoke print MS_OK 65 | txa ; index to accumulator 66 | asl ; x2 67 | tax 68 | lda m_cmd_jumptable,x 69 | sta K_VAR1_L 70 | inx 71 | lda m_cmd_jumptable,x 72 | sta K_VAR1_H 73 | jmp (K_VAR1_L) ; jump to command 74 | m_parse_end: 75 | jmp m_main ; back to mainloop 76 | 77 | .scend 78 | 79 | m_cmd_num: 80 | .byte 12 81 | m_cmd_list: 82 | .byte "acdfghimorsv" 83 | 84 | m_cmd_jumptable: 85 | .word m_cmd_assemble 86 | .word m_cmd_chess 87 | .word m_cmd_disass 88 | .word m_cmd_fill 89 | .word m_cmd_go 90 | .word m_cmd_help 91 | .word m_cmd_input 92 | .word m_cmd_memdump 93 | .word m_cmd_output 94 | .word m_cmd_reset 95 | .word m_cmd_show 96 | .word m_cmd_vtl2 97 | 98 | 99 | m_cmd_chess: 100 | jmp CHESS ; jump to chess program 101 | 102 | m_cmd_vtl2: 103 | jmp v_startx ; jump to vtl2 interpreter 104 | 105 | m_cmd_reset: 106 | jmp ($fffc) ; jump to reset vector 107 | 108 | 109 | m_cmd_show: 110 | ldx #$02 ; bad hack to skip first blank 111 | jsr j_a2b ; parse high byte 112 | sta K_VAR1_H ; store high byte 113 | jsr j_a2b ; parse low byte 114 | sta K_VAR1_L ; store low byte 115 | .invoke linefeed 116 | ldx #0 117 | lda (K_VAR1_L,X) ; load value 118 | pha 119 | jsr j_hex8out ; show hex value 120 | .invoke space 121 | pla 122 | jsr j_bin8out 123 | jmp m_main ; back to parse 124 | 125 | m_cmd_memdump: 126 | ldx #$02 ; bad hack to skip first blank 127 | jsr j_a2b ; parse high byte 128 | sta K_VAR1_H ; store high byte 129 | jsr j_a2b ; parse low byte 130 | sta K_VAR1_L ; store low byte 131 | jsr j_a2b ; parse number of columns 132 | sta K_VAR2_L ; store value 133 | jsr j_a2b ; parse number of rows 134 | sta K_VAR2_H ; store value 135 | jsr m_dump_mem 136 | .invoke linefeed 137 | jmp m_parse_end ; back to parse 138 | 139 | m_cmd_disass: 140 | ldx #$02 ; fist character of address 141 | jsr j_a2b ; parse high byte 142 | sta K_VAR1_H ; store high byte 143 | jsr j_a2b ; parse low byte 144 | sta K_VAR1_L ; store low byte 145 | jmp DSTART ; jump to parsed address 146 | 147 | m_cmd_assemble: 148 | ldx #$02 ; fist character of address 149 | jsr j_a2b ; parse high byte 150 | sta K_VAR1_H ; store high byte 151 | jsr j_a2b ; parse low byte 152 | sta K_VAR1_L ; store low byte 153 | jmp ASTART ; start assembler 154 | 155 | m_cmd_go: 156 | ldx #$02 ; fist character of address 157 | jsr j_a2b ; parse high byte 158 | sta K_VAR1_H ; store high byte 159 | jsr j_a2b ; parse low byte 160 | sta K_VAR1_L ; store low byte 161 | jmp (K_VAR1_L) ; jump to parsed address 162 | 163 | m_cmd_help: 164 | .invoke print MS_HELP1 ; print first help string 165 | .invoke print MS_HELP2 ; print second help string 166 | jmp m_parse_end ; back to parse 167 | 168 | .scope 169 | m_cmd_input: 170 | .invoke linefeed ; 171 | ldx #$02 ; fist character of address 172 | jsr j_a2b ; parse high byte 173 | sta K_VAR1_H ; store high byte 174 | jsr j_a2b ; parse low byte 175 | sta K_VAR1_L ; store low byte 176 | jsr m_clear_buffer ; first clear the buffer 177 | _start: 178 | ldx #$00 ; index 179 | _wait: 180 | jsr j_rchr ; read character 181 | bcs _wait ; wait for character 182 | jsr j_wchr ; output character 183 | cmp #'. ; check if carriage return 184 | beq _end ; branch to end 185 | cmp #AsciiSP ; ignore blank 186 | beq _wait ; 187 | cmp #AsciiLF ; ignore LF 188 | beq _wait ; 189 | cmp #AsciiCR ; ignore CR 190 | beq _wait ; 191 | sta K_BUFFER,x ; store character 192 | inx ; increase index 193 | cpx #$02 ; already second character 194 | bne _wait ; loop for next character 195 | ldx #$00 ; reset index 196 | jsr j_a2b ; parse current byte 197 | ldx #$00 198 | sta (K_VAR1_L,x) ; save byte to destination 199 | inc K_VAR1_L ; increase destination address 200 | bne _start ; next byte 201 | inc K_VAR1_H ; on overflow increase high byte 202 | jmp _start ; next byte 203 | _end: 204 | jmp m_parse_end ; back to parse 205 | .scend 206 | 207 | .scope 208 | m_cmd_output: 209 | .invoke linefeed ; 210 | ldx #$02 ; fist character of address 211 | jsr j_a2b ; parse high byte 212 | sta K_VAR1_H ; store high byte 213 | jsr j_a2b ; parse low byte 214 | sta K_VAR1_L ; store low byte 215 | inx ; skip ':' 216 | jsr j_a2b ; parse high byte 217 | sta K_VAR2_H ; store high byte 218 | jsr j_a2b ; parse low byte 219 | sta K_VAR2_L ; store low byte 220 | ldx #$10 ; 16 values per line 221 | _loop: 222 | txa 223 | pha 224 | ldx #$00 225 | lda (K_VAR1_L,x) ; load value 226 | jsr j_hex8out ; print value 227 | pla 228 | tax 229 | .invoke space ; print separator 230 | dex ; decrement index 231 | bne + ; end of line? 232 | .invoke linefeed ; linefeed 233 | ldx #$10 ; reload index 234 | * jsr m_loop_addr ; next step in loop 235 | bcc _loop ; loop 236 | txa 237 | pha 238 | lda (K_VAR1_L,x) ; laod last value 239 | jsr j_hex8out ; write value 240 | pla 241 | txa 242 | lda #$2e ; '.' 243 | jsr j_wchr ; print final '.' 244 | jmp m_parse_end ; back to parse 245 | .scend 246 | 247 | .scope 248 | m_cmd_fill: 249 | .invoke linefeed ; 250 | ldx #$02 ; fist character of address 251 | jsr j_a2b ; parse high byte 252 | sta K_VAR1_H ; store high byte 253 | jsr j_a2b ; parse low byte 254 | sta K_VAR1_L ; store low byte 255 | inx ; skip ':' 256 | jsr j_a2b ; parse high byte 257 | sta K_VAR2_H ; store high byte 258 | jsr j_a2b ; parse low byte 259 | sta K_VAR2_L ; store low byte 260 | jsr j_a2b ; parse fill byte 261 | _loop: 262 | ldx #$00 263 | sta (K_VAR1_L,x) ; write value 264 | jsr m_loop_addr ; next step in loop 265 | bcc _loop ; loop 266 | sta (K_VAR1_L,x) ; write last value 267 | jmp m_parse_end ; back to parse 268 | .scend 269 | 270 | 271 | ; 272 | ; set cursor to new line and print a prompt 273 | ; 274 | m_show_prompt: 275 | .invoke print MS_PROMPT; 276 | rts 277 | 278 | 279 | 280 | ; 281 | ; clear input buffer 282 | ; 283 | .scope 284 | m_clear_buffer: 285 | pha 286 | txa 287 | pha ; save X 288 | ldx #K_BUF_LEN ; 289 | lda #$00 290 | * sta K_BUFFER,x ; write 00 to buffer position 291 | dex ; decrement index 292 | bne - ; end of buffer ? 293 | sta K_BUF_P ; clear buffer pointer 294 | pla 295 | tax 296 | pla ; restore X 297 | rts ; return 298 | .scend 299 | ; 300 | ; dump a part of the memory as hex dump out 301 | ; 302 | ; @param K_VAR1_L + K_VAR1_H 16bit value of address to dump from 303 | ; @param K_VAR2_L number of bytes per line 304 | ; @param K_VAR2_H number of lines to print 305 | ; 306 | ; @return - 307 | ; 308 | ; A,X,Y are preserved K_VAR* are destroyed 309 | .scope 310 | m_dump_mem: 311 | pha ;save A 312 | txa 313 | pha ;save X 314 | tya 315 | pha ;save Y 316 | ldx K_VAR2_H ;load number of lines 317 | _outer: 318 | .invoke linefeed 319 | ldy K_VAR2_L ;load number of bytes per line 320 | lda K_VAR1_H ;load high byte of address 321 | sta K_VAR3_H ;save high byte for second loop 322 | jsr j_hex8out ;print high byte 323 | lda K_VAR1_L ;load low byte of address 324 | sta K_VAR3_L ;save low byte for second loop 325 | jsr j_hex8out ;print low byte 326 | _inner: 327 | .invoke space ;print " " 328 | stx K_TMP3 ; save X 329 | ldx #$00 330 | lda (K_VAR1_L,x) ;load next byte 331 | jsr j_hex8out ;print byte 332 | ldx K_TMP3 ;restore X 333 | inc K_VAR1_L ;increment address low byte 334 | bne + ;check for turnover 335 | inc K_VAR1_H ;increment address high byte 336 | * dey ;next byte 337 | bne _inner ;end of line? 338 | ;----------------------------------------------------- 339 | ;----------------------------------------------------- 340 | ; 341 | ldy K_VAR2_L ;load number of bytes per line 342 | lda K_VAR3_H ;restore address 343 | sta K_VAR1_H 344 | lda K_VAR3_L 345 | sta K_VAR1_L 346 | .invoke space ;print " " 347 | lda #$7c ;print '|' as ruler 348 | jsr j_wchr 349 | _inner2: 350 | stx K_TMP3 ; save X 351 | ldx #$00 352 | lda (K_VAR1_L,x) ;load next byte 353 | bpl _next1 ; >127 354 | lda #$2e ; show unprintable charachter as '.' 355 | _next1: cmp #$20 ; check if > 32 356 | bcs _print ; 357 | lda #$2e ; show lower then 32 as '.' 358 | _print: jsr j_wchr ;print byte 359 | ldx K_TMP3 ;restore X 360 | inc K_VAR1_L ;increment address low byte 361 | bne + ;check for turnover 362 | inc K_VAR1_H ;increment address high byte 363 | * dey ;next byte 364 | bne _inner2 ;end of line? 365 | lda #$7c ;print '|' as ruler 366 | jsr j_wchr 367 | ;----------------------------------------------------- 368 | ;----------------------------------------------------- 369 | 370 | dex ;next line 371 | bne _outer ;end of lines? 372 | pla ;restore Y 373 | tay 374 | pla ;restore X 375 | tax 376 | pla ;restore A 377 | rts ;return 378 | .scend 379 | 380 | ; 381 | ; loop from one address to a second address by 382 | ; increasing the start address until the end address is reached 383 | ; 384 | ; @param K_VAR1_L + K_VAR1_H 16bit value of address to start from 385 | ; @param K_VAR2_L + K_VAR2_H 16bit value of end address 386 | ; 387 | .scope 388 | m_loop_addr: 389 | pha ; save A 390 | inc K_VAR1_L ; increase low byte 391 | bne + ; no overflow 392 | inc K_VAR1_H ; increase high byte on overflow 393 | * lda K_VAR2_L ; load end value 394 | cmp K_VAR1_L ; compare wiht current address low 395 | bne _end ; not equal 396 | lda K_VAR2_H ; load high value 397 | cmp K_VAR1_H ; compare with current address high 398 | bne _end 399 | sec ; set carry to indicate end of loop 400 | jmp _end2 401 | _end: 402 | clc ; clear carry 403 | _end2: 404 | pla 405 | rts 406 | .scend 407 | 408 | 409 | MS_PROMPT: .byte LINE_END,">",0 410 | MS_WELCOME: .byte "MOUSE MON V 0.8",LINE_END,LINE_END,0 411 | MS_CMD_ERROR: .byte LINE_END,"?unknown command: ",0 412 | MS_OK: .byte " OK",0 413 | MS_HELP1: .byte LINE_END,"commands:", LINE_END,"a - start assembler at address",LINE_END,"c - start microchess", LINE_END,"d - disassemble from address", LINE_END,"f : %val - fill memory with %val", LINE_END,"g - jump to ", LINE_END,"h - this help",LINE_END,"i - input input data to memory '.' ends the input",0 414 | MS_HELP2: .byte LINE_END,"m %cols %rows - dump memory from address", LINE_END,"o : - output memory range", LINE_END,"r - jump to reset vector", LINE_END,"s - show one byte in hex and binary", LINE_END,"v - start VTL2 language", LINE_END," - 16bit address, %xx - 8 bit value",0 415 | -------------------------------------------------------------------------------- /M-OS-6502/SW_chess.asm: -------------------------------------------------------------------------------- 1 | ;*********************************************************************** 2 | ; 3 | ; Kim-1 MicroChess (c) 1976-2005 Peter Jennings, www.benlo.com 4 | ; 5 | ;*********************************************************************** 6 | 7 | ; All rights reserved. 8 | 9 | ; Redistribution and use in source and binary forms, with or without 10 | ; modification, are permitted provided that the following conditions 11 | ; are met: 12 | ; 1. Redistributions of source code must retain the above copyright 13 | ; notice, this list of conditions and the following disclaimer. 14 | ; 2. Redistributions in binary form must reproduce the above copyright 15 | ; notice, this list of conditions and the following disclaimer in the 16 | ; documentation and/or other materials provided with the distribution. 17 | ; 3. The name of the author may not be used to endorse or promote products 18 | ; derived from this software without specific prior written permission. 19 | 20 | ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR 21 | ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 | ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 | ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 | ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 | ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 | ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | ; 32 | ; modified by Daryl Rictor to work over a 33 | ; serial terminal connection, August 2002. 34 | ; 35 | ; Updated with corrections to earlier OCR errors by Bill Forster, August 2005. 36 | ; 37 | ; Adapted by Mario Keller for MOUSE I/O, September 2015 38 | ; 39 | ; publishing this source code was granted by Peter Jennings Oct 2015, but the 40 | ; copyright has still to be respected in all terms. 41 | ; 42 | .alias BOARD $50 43 | .alias BK $60 44 | .alias PIECE $B0 45 | .alias SQUARE $B1 46 | .alias SP2 $B2 47 | .alias SP1 $B3 48 | .alias INCHEK $B4 49 | .alias STATE $B5 50 | .alias MOVEN $B6 51 | .alias REV $B7 52 | .alias OMOVE $DC 53 | .alias WCAP0 $DD 54 | .alias COUNT $DE 55 | .alias BCAP2 $DE 56 | .alias WCAP2 $DF 57 | .alias BCAP1 $E0 58 | .alias WCAP1 $E1 59 | .alias BCAP0 $E2 60 | .alias MOB $E3 61 | .alias MAXC $E4 62 | .alias CC $E5 63 | .alias PCAP $E6 64 | .alias BMOB $E3 65 | .alias BMAXC $E4 66 | .alias BMCC $E5 ; was BCC (TASS doesn't like it as a label) 67 | .alias BMAXP $E6 68 | .alias XMAXC $E8 69 | .alias WMOB $EB 70 | .alias WMAXC $EC 71 | .alias WCC $ED 72 | .alias WMAXP $EE 73 | .alias PMOB $EF 74 | .alias PMAXC $F0 75 | .alias PCC $F1 76 | .alias PCP $F2 77 | .alias OLDKY $F3 78 | .alias BESTP $FB 79 | .alias BESTV $FA 80 | .alias BESTM $F9 81 | .alias DIS1 $FB 82 | .alias DIS2 $FA 83 | .alias DIS3 $F9 84 | .alias temp $FC 85 | ; 86 | ;NOTE THAT $B7 TO $BF, $F4 TO $F8, AND $FC TO $FF ARE 87 | ;AVAILABLE FOR USER EXPANSION AND I/O ROUTINES 88 | ; 89 | ; *=$1000 ; load into RAM @ $1000-$15FF 90 | 91 | LDA #$00 ; REVERSE TOGGLE 92 | STA REV 93 | CHESS: CLD ; INITIALIZE 94 | LDX #$FF ; TWO STACKS 95 | TXS 96 | LDX #$C8 97 | STX SP2 98 | ; 99 | ; ROUTINES TO LIGHT LED 100 | ; DISPLAY AND GET KEY 101 | ; FROM KEYBOARD 102 | ; 103 | OUT: JSR pout ; DISPLAY AND 104 | JSR KIN ; GET INPUT *** my routine waits for a keypress 105 | ; CMP OLDKY ; KEY IN ACC *** no need to debounce 106 | ; BEQ OUT ; (DEBOUNCE) 107 | ; STA OLDKY 108 | ; 109 | CMP #$43 ; [C] 110 | BNE NOSET ; SET UP 111 | LDX #$1F ; BOARD 112 | WHSET: LDA SETW,X ; FROM 113 | STA BOARD,X ; SETW 114 | DEX 115 | BPL WHSET 116 | LDX #$1B ; *ADDED 117 | STX OMOVE ; INITS TO $FF 118 | LDA #$CC ; Display CCC 119 | BNE CLDSP 120 | ; 121 | NOSET: CMP #$45 ; [E] 122 | BNE NOREV ; REVERSE 123 | JSR REVERSE ; BOARD IS 124 | SEC 125 | LDA #$01 126 | SBC REV 127 | STA REV ; TOGGLE REV FLAG 128 | LDA #$EE ; IS 129 | BNE CLDSP 130 | ; 131 | NOREV: CMP #$40 ; [P] 132 | BNE NOGO ; PLAY CHESS 133 | JSR GO 134 | CLDSP: STA DIS1 ; DISPLAY 135 | STA DIS2 ; ACROSS 136 | STA DIS3 ; DISPLAY 137 | BNE CHESS 138 | ; 139 | NOGO: CMP #$0D ; [Enter] 140 | BNE NOMV ; MOVE MAN 141 | JSR MOVEXX ; AS ENTERED 142 | JMP DISP 143 | NOMV: CMP #$41 ; [Q] ***Added to allow game exit*** 144 | BEQ DONE ; quit the game 145 | JMP INPUT ; process move 146 | DONE: JMP MOUSESTART ; exit back to SBC's Monitor 147 | ; 148 | ; THE ROUTINE JANUS DIRECTS THE 149 | ; ANALYSIS BY DETERMINING WHAT 150 | ; SHOULD OCCUR AFTER EACH MOVE 151 | ; GENERATED BY GNM 152 | ; 153 | ; 154 | ; 155 | JANUS: LDX STATE 156 | BMI NOCOUNT 157 | ; 158 | ; THIS ROUTINE COUNTS OCCURRENCES 159 | ; IT DEPENDS UPON STATE TO INDEX 160 | ; THE CORRECT COUNTERS 161 | ; 162 | COUNTS: LDA PIECE 163 | BEQ OVER ; IF STATE=8 164 | CPX #$08 ; DO NOT COUNT 165 | BNE OVER ; BLK MAX CAP 166 | CMP BMAXP ; MOVES FOR 167 | BEQ XRT ; WHITE 168 | ; 169 | OVER: INC MOB,X ; MOBILITY 170 | CMP #$01 ; + QUEEN 171 | BNE NOQ ; FOR TWO 172 | INC MOB,X 173 | ; 174 | NOQ: BVC NOCAP 175 | LDY #$0F ; CALCULATE 176 | LDA SQUARE ; POINTS 177 | ELOOOP: CMP BK,Y ; CAPTURED 178 | BEQ FOUN ; BY THIS 179 | DEY ; MOVE 180 | BPL ELOOOP 181 | FOUN: LDA POINTS,Y 182 | CMP MAXC,X 183 | BCC LESS ; SAVE IF 184 | STY PCAP,X ; BEST THIS 185 | STA MAXC,X ; STATE 186 | ; 187 | LESS: CLC 188 | PHP ; ADD TO 189 | ADC CC,X ; CAPTURE 190 | STA CC,X ; COUNTS 191 | PLP 192 | ; 193 | NOCAP: CPX #$04 194 | BEQ ON4 195 | BMI TREE ;(=00 ONLY) 196 | XRT: RTS 197 | ; 198 | ; GENERATE FURTHER MOVES FOR COUNT 199 | ; AND ANALYSIS 200 | ; 201 | ON4: LDA XMAXC ; SAVE ACTUAL 202 | STA WCAP0 ; CAPTURE 203 | LDA #$00 ; STATE=0 204 | STA STATE 205 | JSR MOVEXX ; GENERATE 206 | JSR REVERSE ; IMMEDIATE 207 | JSR GNMZ ; REPLY MOVES 208 | JSR REVERSE 209 | ; 210 | LDA #$08 ; STATE=8 211 | STA STATE ; GENERATE 212 | ; JSR OHM ; CONTINUATION 213 | JSR UMOVE ; MOVES 214 | ; 215 | JMP STRATGY ; FINAL EVALUATION 216 | NOCOUNT: CPX #$F9 217 | BNE TREE 218 | ; 219 | ; DETERMINE IF THE KING CAN BE 220 | ; TAKEN, USED BY CHKCHK 221 | ; 222 | LDA BK ; IS KING 223 | CMP SQUARE ; IN CHECK? 224 | BNE RETJ ; SET INCHEK=0 225 | LDA #$00 ; IF IT IS 226 | STA INCHEK 227 | RETJ: RTS 228 | ; 229 | ; IF A PIECE HAS BEEN CAPTURED BY 230 | ; A TRIAL MOVE, GENERATE REPLIES & 231 | ; EVALUATE THE EXCHANGE GAIN/LOSS 232 | ; 233 | TREE: BVC RETJ ; NO CAP 234 | LDY #$07 ; (PIECES) 235 | LDA SQUARE 236 | LOOPX: CMP BK,Y 237 | BEQ FOUNX 238 | DEY 239 | BEQ RETJ ; (KING) 240 | BPL LOOPX ; SAVE 241 | FOUNX: LDA POINTS,Y ; BEST CAP 242 | CMP BCAP0,X ; AT THIS 243 | BCC NOMAX ; LEVEL 244 | STA BCAP0,X 245 | NOMAX: DEC STATE 246 | LDA #$FB ; IF STATE=FB 247 | CMP STATE ; TIME TO TURN 248 | BEQ UPTREE ; AROUND 249 | JSR GENRM ; GENERATE FURTHER 250 | UPTREE: INC STATE ; CAPTURES 251 | RTS 252 | ; 253 | ; THE PLAYER'S MOVE IS INPUT 254 | ; 255 | INPUT: CMP #$08 ; NOT A LEGAL 256 | BCS ERROR ; SQUARE # 257 | JSR DISMV 258 | DISP: LDX #$1F 259 | SEARCH: LDA BOARD,X 260 | CMP DIS2 261 | BEQ HERE ; DISPLAY 262 | DEX ; PIECE AT 263 | BPL SEARCH ; FROM 264 | HERE: STX DIS1 ; SQUARE 265 | STX PIECE 266 | ERROR: JMP CHESS 267 | ; 268 | ; GENERATE ALL MOVES FOR ONE 269 | ; SIDE, CALL JANUS AFTER EACH 270 | ; ONE FOR NEXT STE? 271 | ; 272 | ; 273 | GNMZ: LDX #$10 ; CLEAR 274 | GNMX: LDA #$00 ; COUNTERS 275 | CLEAR: STA COUNT,X 276 | DEX 277 | BPL CLEAR 278 | ; 279 | GNM: LDA #$10 ; SET UP 280 | STA PIECE ; PIECE 281 | NEWP: DEC PIECE ; NEW PIECE 282 | BPL NEX ; ALL DONE? 283 | RTS ; #NAME? 284 | ; 285 | NEX: JSR RESET ; READY 286 | LDY PIECE ; GET PIECE 287 | LDX #$08 288 | STX MOVEN ; COMMON START 289 | CPY #$08 ; WHAT IS IT? 290 | BPL PAWN ; PAWN 291 | CPY #$06 292 | BPL KNIGHT ; KNIGHT 293 | CPY #$04 294 | BPL BISHOP ; BISHOP 295 | CPY #$01 296 | BEQ QUEEN ; QUEEN 297 | BPL ROOK ; ROOK 298 | ; 299 | KING: JSR SNGMV ; MUST BE KING! 300 | BNE KING ; MOVES 301 | BEQ NEWP ; 8 TO 1 302 | QUEEN: JSR LINE 303 | BNE QUEEN ; MOVES 304 | BEQ NEWP ; 8 TO 1 305 | ; 306 | ROOK: LDX #$04 307 | STX MOVEN ; MOVES 308 | AGNR: JSR LINE ; 4 TO 1 309 | BNE AGNR 310 | BEQ NEWP 311 | ; 312 | BISHOP: JSR LINE 313 | LDA MOVEN ; MOVES 314 | CMP #$04 ; 8 TO 5 315 | BNE BISHOP 316 | BEQ NEWP 317 | ; 318 | KNIGHT: LDX #$10 319 | STX MOVEN ; MOVES 320 | AGNN: JSR SNGMV ; 16 TO 9 321 | LDA MOVEN 322 | CMP #$08 323 | BNE AGNN 324 | BEQ NEWP 325 | ; 326 | PAWN: LDX #$06 327 | STX MOVEN 328 | P1: JSR CMOVE ; RIGHT CAP? 329 | BVC P2 330 | BMI P2 331 | JSR JANUS ; YES 332 | P2: JSR RESET 333 | DEC MOVEN ; LEFT CAP? 334 | LDA MOVEN 335 | CMP #$05 336 | BEQ P1 337 | P3: JSR CMOVE ; AHEAD 338 | BVS NEWP ; ILLEGAL 339 | BMI NEWP 340 | JSR JANUS 341 | LDA SQUARE ; GETS TO 342 | AND #$F0 ; 3RD RANK? 343 | CMP #$20 344 | BEQ P3 ; DO DOUBLE 345 | JMP NEWP 346 | ; 347 | ; CALCULATE SINGLE STEP MOVES 348 | ; FOR K,N 349 | ; 350 | SNGMV: JSR CMOVE ; CALC MOVE 351 | BMI ILL1 ; -IF LEGAL 352 | JSR JANUS ; -EVALUATE 353 | ILL1: JSR RESET 354 | DEC MOVEN 355 | RTS 356 | ; 357 | ; CALCULATE ALL MOVES DOWN A 358 | ; STRAIGHT LINE FOR Q,B,R 359 | ; 360 | LINE: JSR CMOVE ; CALC MOVE 361 | BCC OVL ; NO CHK 362 | BVC LINE ; NOCAP 363 | OVL: BMI ILL ; RETURN 364 | PHP 365 | JSR JANUS ; EVALUATE POSN 366 | PLP 367 | BVC LINE ; NOT A CAP 368 | ILL: JSR RESET ; LINE STOPPED 369 | DEC MOVEN ; NEXT DIR 370 | RTS 371 | ; 372 | ; EXCHANGE SIDES FOR REPLY 373 | ; ANALYSIS 374 | ; 375 | REVERSE: LDX #$0F 376 | ETC: SEC 377 | LDY BK,X ; SUBTRACT 378 | LDA #$77 ; POSITION 379 | SBC BOARD,X ; FROM 77 380 | STA BK,X 381 | STY BOARD,X ; AND 382 | SEC 383 | LDA #$77 ; EXCHANGE 384 | SBC BOARD,X ; PIECES 385 | STA BOARD,X 386 | DEX 387 | BPL ETC 388 | RTS 389 | ; 390 | ; CMOVE CALCULATES THE TO SQUARE 391 | ; USING SQUARE AND THE MOVE 392 | ; TABLE FLAGS SET AS FOLLOWS: 393 | ; N#NAME? MOVE 394 | ; V#NAME? (LEGAL UNLESS IN CR) 395 | ; C#NAME? BECAUSE OF CHECK 396 | ; [MY &THANKS TO JIM BUTTERFIELD 397 | ; WHO WROTE THIS MORE EFFICIENT 398 | ; VERSION OF CMOVE) 399 | ; 400 | CMOVE: LDA SQUARE ; GET SQUARE 401 | LDX MOVEN ; MOVE POINTER 402 | CLC 403 | ADC MOVEX,X ; MOVE LIST 404 | STA SQUARE ; NEW POS'N 405 | AND #$88 406 | BNE ILLEGAL ; OFF BOARD 407 | LDA SQUARE 408 | ; 409 | LDX #$20 410 | LOOP: DEX ; IS TO 411 | BMI NO ; SQUARE 412 | CMP BOARD,X ; OCCUPIED? 413 | BNE LOOP 414 | ; 415 | CPX #$10 ; BY SELF? 416 | BMI ILLEGAL 417 | ; 418 | LDA #$7F ; MUST BE CAP! 419 | ADC #$01 ; SET V FLAG 420 | BVS SPX ; (JMP) 421 | ; 422 | NO: CLV ; NO CAPTURE 423 | ; 424 | SPX: LDA STATE ; SHOULD WE 425 | BMI RETL ; DO THE 426 | CMP #$08 ; CHECK CHECK? 427 | BPL RETL 428 | ; 429 | ; CHKCHK REVERSES SIDES 430 | ; AND LOOKS FOR A KING 431 | ; CAPTURE TO INDICATE 432 | ; ILLEGAL MOVE BECAUSE OF 433 | ; CHECK SINCE THIS IS 434 | ; TIME CONSUMING, IT IS NOT 435 | ; ALWAYS DONE 436 | ; 437 | CHKCHK: PHA ; STATE #392 438 | PHP 439 | LDA #$F9 440 | STA STATE ; GENERATE 441 | STA INCHEK ; ALL REPLY 442 | JSR MOVEXX ; MOVES TO 443 | JSR REVERSE ; SEE IF KING 444 | JSR GNM ; IS IN 445 | JSR RUM ; CHECK 446 | PLP 447 | PLA 448 | STA STATE 449 | LDA INCHEK 450 | BMI RETL ; NO - SAFE 451 | SEC ; YES - IN CHK 452 | LDA #$FF 453 | RTS 454 | ; 455 | RETL: CLC ; LEGAL 456 | LDA #$00 ; RETURN 457 | RTS 458 | ; 459 | ILLEGAL: LDA #$FF 460 | CLC ; ILLEGAL 461 | CLV ; RETURN 462 | RTS 463 | ; 464 | ; REPLACE PIECE ON CORRECT SQUARE 465 | ; 466 | RESET: LDX PIECE ; GET LOGAT 467 | LDA BOARD,X ; FOR PIECE 468 | STA SQUARE ; FROM BOARD 469 | RTS 470 | ; 471 | ; 472 | ; 473 | GENRM: JSR MOVEXX ; MAKE MOVE 474 | GENR2: JSR REVERSE ; REVERSE BOARD 475 | JSR GNM ; GENERATE MOVES 476 | RUM: JSR REVERSE ; REVERSE BACK 477 | ; 478 | ; ROUTINE TO UNMAKE A MOVE MADE BY 479 | ; MOVE 480 | ; 481 | UMOVE: TSX ; UNMAKE MOVE 482 | STX SP1 483 | LDX SP2 ; EXCHANGE 484 | TXS ; STACKS 485 | PLA ; MOVEN 486 | STA MOVEN 487 | PLA ; CAPTURED 488 | STA PIECE ; PIECE 489 | TAX 490 | PLA ; FROM SQUARE 491 | STA BOARD,X 492 | PLA ; PIECE 493 | TAX 494 | PLA ; TO SOUARE 495 | STA SQUARE 496 | STA BOARD,X 497 | JMP STRV 498 | ; 499 | ; THIS ROUTINE MOVES PIECE 500 | ; TO SQUARE, PARAMETERS 501 | ; ARE SAVED IN A STACK TO UNMAKE 502 | ; THE MOVE LATER 503 | ; 504 | MOVEXX: TSX 505 | STX SP1 ; SWITCH 506 | LDX SP2 ; STACKS 507 | TXS 508 | LDA SQUARE 509 | PHA ; TO SQUARE 510 | TAY 511 | LDX #$1F 512 | CHECK: CMP BOARD,X ; CHECK FOR 513 | BEQ TAKE ; CAPTURE 514 | DEX 515 | BPL CHECK 516 | TAKE: LDA #$CC 517 | STA BOARD,X 518 | TXA ; CAPTURED 519 | PHA ; PIECE 520 | LDX PIECE 521 | LDA BOARD,X 522 | STY BOARD,X ; FROM 523 | PHA ; SQUARE 524 | TXA 525 | PHA ; PIECE 526 | LDA MOVEN 527 | PHA ; MOVEN 528 | STRV: TSX 529 | STX SP2 ; SWITCH 530 | LDX SP1 ; STACKS 531 | TXS ; BACK 532 | RTS 533 | ; 534 | ; CONTINUATION OF SUB STRATGY 535 | ; -CHECKS FOR CHECK OR CHECKMATE 536 | ; AND ASSIGNS VALUE TO MOVE 537 | ; 538 | CKMATE: LDY BMAXC ; CAN BLK CAP 539 | CPX POINTS ; MY KING? 540 | BNE NOCHEK 541 | LDA #$00 ; GULP! 542 | BEQ RETV ; DUMB MOVE! 543 | ; 544 | NOCHEK: LDX BMOB ; IS BLACK 545 | BNE RETV ; UNABLE TO 546 | LDX WMAXP ; MOVE AND 547 | BNE RETV ; KING IN CH? 548 | LDA #$FF ; YES! MATE 549 | ; 550 | RETV: LDX #$04 ; RESTORE 551 | STX STATE ; STATE=4 552 | ; 553 | ; THE VALUE OF THE MOVE (IN ACCU) 554 | ; IS COMPARED TO THE BEST MOVE AND 555 | ; REPLACES IT IF IT IS BETTER 556 | ; 557 | PUSH: CMP BESTV ; IS THIS BEST 558 | BCC RETP ; MOVE SO FAR? 559 | BEQ RETP 560 | STA BESTV ; YES! 561 | LDA PIECE ; SAVE IT 562 | STA BESTP 563 | LDA SQUARE 564 | STA BESTM ; FLASH DISPLAY 565 | RETP: LDA #$2E ; print ... instead of flashing disp 566 | Jmp syschout ; print . and return 567 | ; 568 | ; MAIN PROGRAM TO PLAY CHESS 569 | ; PLAY FROM OPENING OR THINK 570 | ; 571 | GO: LDX OMOVE ; OPENING? 572 | BMI NOOPEN ; -NO *ADD CHANGE FROM BPL 573 | LDA DIS3 ; -YES WAS 574 | CMP OPNING,X ; OPPONENT'S 575 | BNE END ; MOVE OK? 576 | DEX 577 | LDA OPNING,X ; GET NEXT 578 | STA DIS1 ; CANNED 579 | DEX ; OPENING MOVE 580 | LDA OPNING,X 581 | STA DIS3 ; DISPLAY IT 582 | DEX 583 | STX OMOVE ; MOVE IT 584 | BNE MV2 ; (JMP) 585 | ; 586 | END: LDA #$FF ; *ADD - STOP CANNED MOVES 587 | STA OMOVE ; FLAG OPENING 588 | NOOPEN: LDX #$0C ; FINISHED 589 | STX STATE ; STATE=C 590 | STX BESTV ; CLEAR BESTV 591 | LDX #$14 ; GENERATE P 592 | JSR GNMX ; MOVES 593 | ; 594 | LDX #$04 ; STATE=4 595 | STX STATE ; GENERATE AND 596 | JSR GNMZ ; TEST AVAILABLE 597 | ; 598 | ; MOVES 599 | ; 600 | LDX BESTV ; GET BEST MOVE 601 | CPX #$0F ; IF NONE 602 | BCC MATE ; OH OH! 603 | ; 604 | MV2: LDX BESTP ; MOVE 605 | LDA BOARD,X ; THE 606 | STA BESTV ; BEST 607 | STX PIECE ; MOVE 608 | LDA BESTM 609 | STA SQUARE ; AND DISPLAY 610 | JSR MOVEXX ; IT 611 | JMP CHESS 612 | ; 613 | MATE: LDA #$FF ; RESIGN 614 | RTS ; OR STALEMATE 615 | ; 616 | ; SUBROUTINE TO ENTER THE 617 | ; PLAYER'S MOVE 618 | ; 619 | DISMV: LDX #$04 ; ROTATE 620 | DROL: ASL DIS3 ; KEY 621 | ROL DIS2 ; INTO 622 | DEX ; DISPLAY 623 | BNE DROL ; 624 | ORA DIS3 625 | STA DIS3 626 | STA SQUARE 627 | RTS 628 | ; 629 | ; THE FOLLOWING SUBROUTINE ASSIGNS 630 | ; A VALUE TO THE MOVE UNDER 631 | ; CONSIDERATION AND RETURNS IT IN 632 | ; THE ACCUMULATOR 633 | ; 634 | 635 | STRATGY: CLC 636 | LDA #$80 637 | ADC WMOB ; PARAMETERS 638 | ADC WMAXC ; WITH WHEIGHT 639 | ADC WCC ; OF O25 640 | ADC WCAP1 641 | ADC WCAP2 642 | SEC 643 | SBC PMAXC 644 | SBC PCC 645 | SBC BCAP0 646 | SBC BCAP1 647 | SBC BCAP2 648 | SBC PMOB 649 | SBC BMOB 650 | BCS POS ; UNDERFLOW 651 | LDA #$00 ; PREVENTION 652 | POS: LSR 653 | CLC ; ************** 654 | ADC #$40 655 | ADC WMAXC ; PARAMETERS 656 | ADC WCC ; WITH WEIGHT 657 | SEC ; OF 05 658 | SBC BMAXC 659 | LSR ; ************** 660 | CLC 661 | ADC #$90 662 | ADC WCAP0 ; PARAMETERS 663 | ADC WCAP0 ; WITH WEIGHT 664 | ADC WCAP0 ; OF 10 665 | ADC WCAP0 666 | ADC WCAP1 667 | SEC ; [UNDER OR OVER- 668 | SBC BMAXC ; FLOW MAY OCCUR 669 | SBC BMAXC ; FROM THIS 670 | SBC BMCC ; SECTION] 671 | SBC BMCC 672 | SBC BCAP1 673 | LDX SQUARE ; *************** 674 | CPX #$33 675 | BEQ POSN ; POSITION 676 | CPX #$34 ; BONUS FOR 677 | BEQ POSN ; MOVE TO 678 | CPX #$22 ; CENTRE 679 | BEQ POSN ; OR 680 | CPX #$25 ; OUT OF 681 | BEQ POSN ; BACK RANK 682 | LDX PIECE 683 | BEQ NOPOSN 684 | LDY BOARD,X 685 | CPY #$10 686 | BPL NOPOSN 687 | POSN: CLC 688 | ADC #$02 689 | NOPOSN: JMP CKMATE ; CONTINUE 690 | 691 | 692 | ;----------------------------------------------------------------- 693 | ; The following routines were added to allow text-based board 694 | ; display over a standard RS-232 port. 695 | ; 696 | POUT: jsr pout9 ; print CRLF 697 | jsr pout13 ; print copyright 698 | JSR POUT10 ; print column labels 699 | LDY #$00 ; init board location 700 | JSR POUT5 ; print board horz edge 701 | POUT1: lDA #$7C ; print vert edge 702 | JSR syschout ; PRINT ONE ASCII CHR - SPACE 703 | LDX #$1F 704 | POUT2: TYA ; scan the pieces for a location match 705 | CMP BOARD,X ; match found? 706 | BEQ POUT4 ; yes; print the piece's color and type 707 | DEX ; no 708 | BPL POUT2 ; if not the last piece, try again 709 | tya ; empty square 710 | and #$01 ; odd or even column? 711 | sta temp ; save it 712 | tya ; is the row odd or even 713 | lsr ; shift column right 4 spaces 714 | lsr ; 715 | lsr ; 716 | lsr ; 717 | and #$01 ; strip LSB 718 | clc ; 719 | adc temp ; combine row & col to determine square color 720 | and #$01 ; is board square white or blk? 721 | bne pout25 ; black, print space 722 | lda #$2A ; white, print * 723 | .byte $2c ; used to skip over LDA #$20 724 | POUT25: LDA #$20 ; ASCII space 725 | JSR syschout ; PRINT ONE ASCII CHR - SPACE 726 | JSR syschout ; PRINT ONE ASCII CHR - SPACE 727 | POUT3: INY ; 728 | TYA ; get row number 729 | AND #$08 ; have we completed the row? 730 | BEQ POUT1 ; no, do next column 731 | LDA #$7C ; yes, put the right edge on 732 | JSR syschout ; PRINT ONE ASCII CHR - | 733 | jsr pout12 ; print row number 734 | JSR POUT9 ; print CRLF 735 | JSR POUT5 ; print bottom edge of board 736 | CLC ; 737 | TYA ; 738 | ADC #$08 ; point y to beginning of next row 739 | TAY ; 740 | CPY #$80 ; was that the last row? 741 | BEQ POUT8 ; yes, print the LED values 742 | BNE POUT1 ; no, do new row 743 | 744 | POUT4: LDA REV ; print piece's color & type 745 | BEQ POUT41 ; 746 | LDA cpl+16,X ; 747 | BNE POUT42 ; 748 | POUT41: LDA cpl,x ; 749 | POUT42: JSR syschout ; 750 | lda cph,x ; 751 | jsr syschout ; 752 | BNE POUT3 ; branch always 753 | 754 | POUT5: TXA ; print "-----...-----" 755 | PHA 756 | LDX #$19 757 | LDA #$2D 758 | POUT6: JSR syschout ; PRINT ONE ASCII CHR - "-" 759 | DEX 760 | BNE POUT6 761 | PLA 762 | TAX 763 | JSR POUT9 764 | RTS 765 | 766 | POUT8: jsr pout10 ; 767 | LDA $FB 768 | JSR syshexout ; PRINT 1 BYTE AS 2 HEX CHRS 769 | LDA #$20 770 | JSR syschout ; PRINT ONE ASCII CHR - SPACE 771 | LDA $FA 772 | JSR syshexout ; PRINT 1 BYTE AS 2 HEX CHRS 773 | LDA #$20 774 | JSR syschout ; PRINT ONE ASCII CHR - SPACE 775 | LDA $F9 776 | JSR syshexout ; PRINT 1 BYTE AS 2 HEX CHRS 777 | 778 | POUT9: LDA #LINE_END 779 | JSR syschout ; PRINT ONE ASCII CHR - CR 780 | ;LDA #$0A 781 | ;JSR syschout ; PRINT ONE ASCII CHR - LF 782 | RTS 783 | 784 | pout10: ldx #$00 ; print the column labels 785 | POUT11: lda #$20 ; 00 01 02 03 ... 07 786 | jsr syschout 787 | txa 788 | jsr syshexout 789 | INX 790 | CPX #$08 791 | BNE POUT11 792 | BEQ POUT9 793 | POUT12: TYA 794 | and #$70 795 | JSR syshexout 796 | rts 797 | 798 | Pout13: ldx #$00 ; Print the copyright banner 799 | Pout14: lda banner,x 800 | beq POUT15 801 | jsr syschout 802 | inx 803 | bne POUT14 804 | POUT15: rts 805 | 806 | KIN: LDA #$3F 807 | JSR syschout ; PRINT ONE ASCII CHR - ? 808 | JSR syskin ; GET A KEYSTROKE FROM SYSTEM 809 | AND #$4F ; MASK 0-7, AND ALPHA'S 810 | RTS 811 | 812 | syskin: jsr j_rchr ; read input 813 | bcs syskin ; wait for input 814 | rts 815 | syschout: jsr j_wchr 816 | rts 817 | syshexout: jsr j_hex8out 818 | rts 819 | ;syskin: jmp ($03eb) ; SBC's get a key routine 820 | ;syschout: jmp ($03f1) ; SBC's chr ouput routine 821 | ;syshexout: jmp $e962 ; SBC's HEX byte output (Print1Byte) 822 | 823 | banner: .byte "MicroChess (c) 1996-2002 Peter Jennings, peterj@benlo.com" 824 | .byte $0d, $0a, $00 825 | cpl: .byte "WWWWWWWWWWWWWWWWBBBBBBBBBBBBBBBBWWWWWWWWWWWWWWWW" 826 | cph: .byte "KQCCBBRRPPPPPPPPKQCCBBRRPPPPPPPP" 827 | .byte $00 828 | ; 829 | ; end of added code 830 | ; 831 | ; BLOCK DATA 832 | ; *= $1500 833 | SETW: .byte $03, $04, $00, $07, $02, $05, $01, $06 834 | .byte $10, $17, $11, $16, $12, $15, $14, $13 835 | .byte $73, $74, $70, $77, $72, $75, $71, $76 836 | .byte $60, $67, $61, $66, $62, $65, $64, $63 837 | 838 | MOVEX: .byte $00, $F0, $FF, $01, $10, $11, $0F, $EF, $F1 839 | .byte $DF, $E1, $EE, $F2, $12, $0E, $1F, $21 840 | 841 | POINTS: .byte $0B, $0A, $06, $06, $04, $04, $04, $04 842 | .byte $02, $02, $02, $02, $02, $02, $02, $02 843 | 844 | OPNING: .byte $99, $25, $0B, $25, $01, $00, $33, $25 845 | .byte $07, $36, $34, $0D, $34, $34, $0E, $52 846 | .byte $25, $0D, $45, $35, $04, $55, $22, $06 847 | .byte $43, $33, $0F, $CC 848 | 849 | ; 850 | ; 851 | ; end of file 852 | ; 853 | -------------------------------------------------------------------------------- /Arduino/arduino_6502_mouse/cpu.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 6502 Emulator from Mike Chambers 4 | * 5 | * permission to use an share was granted but the 6 | * rights are still held by Mike. 7 | * 8 | * 9 | * details found in the Arduino Forum 10 | * http://forum.arduino.cc/index.php?topic=193216.0 11 | * 12 | * modified by Mario Keller 2016 for MOUSE2Go 13 | * 14 | */ 15 | 16 | #include 17 | #include 18 | 19 | #define uchar unsigned char 20 | #define NULL (void *) 0 21 | 22 | #include "rom_image.h" 23 | 24 | extern void serout(uint8_t value); 25 | extern void clearkey(); 26 | extern uint8_t getkey(); 27 | 28 | //take care the the smalest size ist set 29 | #ifndef RAM_SIZE 30 | #define RAM_SIZE 1536 //Pro 328 31 | #endif 32 | 33 | //#define RAM_SIZE 4096 //Mega 1280/2560 34 | //#define RAM_SIZE 32768 //Due 35 | 36 | //6502 defines 37 | //#define UNDOCUMENTED //when this is defined, undocumented opcodes are handled. 38 | //otherwise, they're simply treated as NOPs. 39 | 40 | //#define USE_TIMING //slower, but allows you to specify number of cycles to run for exec6502 41 | //rather than simply a number of instructions. also uses a little more 42 | //program memory when enabled. 43 | 44 | #define FLAG_CARRY 0x01 45 | #define FLAG_ZERO 0x02 46 | #define FLAG_INTERRUPT 0x04 47 | #define FLAG_DECIMAL 0x08 48 | #define FLAG_BREAK 0x10 49 | #define FLAG_CONSTANT 0x20 50 | #define FLAG_OVERFLOW 0x40 51 | #define FLAG_SIGN 0x80 52 | 53 | #define BASE_STACK 0x100 54 | 55 | //defining and input and output address for getting and putting 56 | //characters from / to the outside world 57 | //to save space they are located right before the NMI vector 58 | #define GETC 0xfff9 59 | #define PUTC 0xfff8 60 | 61 | #define saveaccum(n) a = (uint8_t)((n) & 0x00FF) 62 | 63 | //flag modifier macros 64 | #define setcarry() cpustatus |= FLAG_CARRY 65 | #define clearcarry() cpustatus &= (~FLAG_CARRY) 66 | #define setzero() cpustatus |= FLAG_ZERO 67 | #define clearzero() cpustatus &= (~FLAG_ZERO) 68 | #define setinterrupt() cpustatus |= FLAG_INTERRUPT 69 | #define clearinterrupt() cpustatus &= (~FLAG_INTERRUPT) 70 | #define setdecimal() cpustatus |= FLAG_DECIMAL 71 | #define cleardecimal() cpustatus &= (~FLAG_DECIMAL) 72 | #define setoverflow() cpustatus |= FLAG_OVERFLOW 73 | #define clearoverflow() cpustatus &= (~FLAG_OVERFLOW) 74 | #define setsign() cpustatus |= FLAG_SIGN 75 | #define clearsign() cpustatus &= (~FLAG_SIGN) 76 | 77 | 78 | //flag calculation macros 79 | #define zerocalc(n) { if ((n) & 0x00FF) clearzero(); else setzero(); } 80 | 81 | #define signcalc(n) { if ((n) & 0x0080) setsign(); else clearsign(); } 82 | 83 | #define carrycalc(n) { if ((n) & 0xFF00) setcarry(); else clearcarry(); } 84 | 85 | #define overflowcalc(n, m, o) { if (((n) ^ (uint16_t)(m)) & ((n) ^ (o)) & 0x0080) setoverflow(); else clearoverflow(); } 86 | 87 | 88 | //6502 CPU registers 89 | uint16_t pc; 90 | uint8_t sp, a, x, y, cpustatus; 91 | 92 | 93 | //helper variables 94 | uint32_t instructions = 0; //keep track of total instructions executed 95 | int32_t clockticks6502 = 0, clockgoal6502 = 0; 96 | uint16_t oldpc, ea, reladdr, value, result; 97 | uint8_t opcode, oldcpustatus, useaccum; 98 | 99 | //make $7FFC to $7FFF usable as RAM regardless of ammount of real memory 100 | //virtual memory for storing NMI and IRQ vectors out of ROM 101 | // $7FFC is used as NMI vector in M-OS 102 | // $7FFE is used as IRQ vector in M-OS 103 | #define SOFT_VECTORS_START 0x7ffc 104 | #define SOFT_VECTORS_END 0x7fff 105 | uint8_t SOFT_VECTORS[4]; 106 | 107 | uint8_t RAM[RAM_SIZE]; 108 | 109 | uint8_t read6502(uint16_t address) { 110 | uint16_t BIOSaddr; 111 | uint8_t tempval = 0; 112 | //virtual memory for storing NMI and IRQ vectors out of ROM 113 | if(address >= SOFT_VECTORS_START && address <= SOFT_VECTORS_END) { 114 | return SOFT_VECTORS[address - SOFT_VECTORS_START]; 115 | } 116 | 117 | //external hook to read a byte from "outside" from a specific address 118 | if (address == GETC) { //MOUSE simulated ASCII input 119 | tempval = getkey(); 120 | clearkey(); 121 | return(tempval); 122 | } 123 | 124 | if (address >= 0xE000) { 125 | BIOSaddr = address - 0xE000; 126 | return(pgm_read_byte_near(BIOS + BIOSaddr)); 127 | } 128 | 129 | if (address < RAM_SIZE) return(RAM[address]); 130 | return(0); 131 | } 132 | void write6502(uint16_t address, uint8_t value) { 133 | //virtual memory for storing NMI and IRQ vectors out of ROM 134 | if(address >= SOFT_VECTORS_START && address <= SOFT_VECTORS_END) { 135 | SOFT_VECTORS[address - SOFT_VECTORS_START] = value; 136 | } 137 | 138 | if (address < RAM_SIZE) RAM[address] = value; 139 | 140 | //external hook to write a byte to the "outside" at a specific address 141 | if (address == PUTC) { //EhBASIC+mouse simulated ASIC output 142 | serout(value); 143 | } 144 | 145 | } 146 | 147 | //a few general functions used by various other functions 148 | void push16(uint16_t pushval) { 149 | write6502(BASE_STACK + sp, (pushval >> 8) & 0xFF); 150 | write6502(BASE_STACK + ((sp - 1) & 0xFF), pushval & 0xFF); 151 | sp -= 2; 152 | } 153 | 154 | void push8(uint8_t pushval) { 155 | write6502(BASE_STACK + sp--, pushval); 156 | } 157 | 158 | uint16_t pull16() { 159 | uint16_t temp16; 160 | temp16 = read6502(BASE_STACK + ((sp + 1) & 0xFF)) | ((uint16_t)read6502(BASE_STACK + ((sp + 2) & 0xFF)) << 8); 161 | sp += 2; 162 | return(temp16); 163 | } 164 | 165 | uint8_t pull8() { 166 | return (read6502(BASE_STACK + ++sp)); 167 | } 168 | 169 | void reset6502() { 170 | pc = (uint16_t)read6502(0xFFFC) | ((uint16_t)read6502(0xFFFD) << 8); 171 | a = 0; 172 | x = 0; 173 | y = 0; 174 | sp = 0xFD; 175 | cpustatus |= FLAG_CONSTANT; 176 | } 177 | 178 | //addressing mode functions, calculates effective addresses 179 | void imp() { //implied 180 | } 181 | 182 | void acc() { //accumulator 183 | useaccum = 1; 184 | } 185 | 186 | void imm() { //immediate 187 | ea = pc++; 188 | } 189 | 190 | void zp() { //zero-page 191 | ea = (uint16_t)read6502((uint16_t)pc++); 192 | } 193 | 194 | void zpx() { //zero-page,X 195 | ea = ((uint16_t)read6502((uint16_t)pc++) + (uint16_t)x) & 0xFF; //zero-page wraparound 196 | } 197 | 198 | void zpy() { //zero-page,Y 199 | ea = ((uint16_t)read6502((uint16_t)pc++) + (uint16_t)y) & 0xFF; //zero-page wraparound 200 | } 201 | 202 | void rel() { //relative for branch ops (8-bit immediate value, sign-extended) 203 | reladdr = (uint16_t)read6502(pc++); 204 | if (reladdr & 0x80) reladdr |= 0xFF00; 205 | } 206 | 207 | void abso() { //absolute 208 | ea = (uint16_t)read6502(pc) | ((uint16_t)read6502(pc+1) << 8); 209 | pc += 2; 210 | } 211 | 212 | void absx() { //absolute,X 213 | uint16_t startpage; 214 | ea = ((uint16_t)read6502(pc) | ((uint16_t)read6502(pc+1) << 8)); 215 | startpage = ea & 0xFF00; 216 | ea += (uint16_t)x; 217 | 218 | pc += 2; 219 | } 220 | 221 | void absy() { //absolute,Y 222 | uint16_t startpage; 223 | ea = ((uint16_t)read6502(pc) | ((uint16_t)read6502(pc+1) << 8)); 224 | startpage = ea & 0xFF00; 225 | ea += (uint16_t)y; 226 | 227 | pc += 2; 228 | } 229 | 230 | void ind() { //indirect 231 | uint16_t eahelp, eahelp2; 232 | eahelp = (uint16_t)read6502(pc) | (uint16_t)((uint16_t)read6502(pc+1) << 8); 233 | eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); //replicate 6502 page-boundary wraparound bug 234 | ea = (uint16_t)read6502(eahelp) | ((uint16_t)read6502(eahelp2) << 8); 235 | pc += 2; 236 | } 237 | 238 | void indx() { // (indirect,X) 239 | uint16_t eahelp; 240 | eahelp = (uint16_t)(((uint16_t)read6502(pc++) + (uint16_t)x) & 0xFF); //zero-page wraparound for table pointer 241 | ea = (uint16_t)read6502(eahelp & 0x00FF) | ((uint16_t)read6502((eahelp+1) & 0x00FF) << 8); 242 | } 243 | 244 | void indy() { // (indirect),Y 245 | uint16_t eahelp, eahelp2, startpage; 246 | eahelp = (uint16_t)read6502(pc++); 247 | eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); //zero-page wraparound 248 | ea = (uint16_t)read6502(eahelp) | ((uint16_t)read6502(eahelp2) << 8); 249 | startpage = ea & 0xFF00; 250 | ea += (uint16_t)y; 251 | 252 | } 253 | 254 | static uint16_t getvalue() { 255 | if (useaccum) return((uint16_t)a); 256 | else return((uint16_t)read6502(ea)); 257 | } 258 | 259 | static uint16_t getvalue16() { 260 | return((uint16_t)read6502(ea) | ((uint16_t)read6502(ea+1) << 8)); 261 | } 262 | 263 | void putvalue(uint16_t saveval) { 264 | if (useaccum) a = (uint8_t)(saveval & 0x00FF); 265 | else write6502(ea, (saveval & 0x00FF)); 266 | } 267 | 268 | 269 | //instruction handler functions 270 | void adc() { 271 | value = getvalue(); 272 | result = (uint16_t)a + value + (uint16_t)(cpustatus & FLAG_CARRY); 273 | 274 | carrycalc(result); 275 | zerocalc(result); 276 | overflowcalc(result, a, value); 277 | signcalc(result); 278 | 279 | #ifndef NES_CPU 280 | if (cpustatus & FLAG_DECIMAL) { 281 | clearcarry(); 282 | 283 | if ((a & 0x0F) > 0x09) { 284 | a += 0x06; 285 | } 286 | if ((a & 0xF0) > 0x90) { 287 | a += 0x60; 288 | setcarry(); 289 | } 290 | 291 | clockticks6502++; 292 | } 293 | #endif 294 | 295 | saveaccum(result); 296 | } 297 | 298 | void op_and() { 299 | value = getvalue(); 300 | result = (uint16_t)a & value; 301 | 302 | zerocalc(result); 303 | signcalc(result); 304 | 305 | saveaccum(result); 306 | } 307 | 308 | void asl() { 309 | value = getvalue(); 310 | result = value << 1; 311 | 312 | carrycalc(result); 313 | zerocalc(result); 314 | signcalc(result); 315 | 316 | putvalue(result); 317 | } 318 | 319 | void bcc() { 320 | if ((cpustatus & FLAG_CARRY) == 0) { 321 | oldpc = pc; 322 | pc += reladdr; 323 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 324 | else clockticks6502++; 325 | } 326 | } 327 | 328 | void bcs() { 329 | if ((cpustatus & FLAG_CARRY) == FLAG_CARRY) { 330 | oldpc = pc; 331 | pc += reladdr; 332 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 333 | else clockticks6502++; 334 | } 335 | } 336 | 337 | void beq() { 338 | if ((cpustatus & FLAG_ZERO) == FLAG_ZERO) { 339 | oldpc = pc; 340 | pc += reladdr; 341 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 342 | else clockticks6502++; 343 | } 344 | } 345 | 346 | void op_bit() { 347 | value = getvalue(); 348 | result = (uint16_t)a & value; 349 | 350 | zerocalc(result); 351 | cpustatus = (cpustatus & 0x3F) | (uint8_t)(value & 0xC0); 352 | } 353 | 354 | void bmi() { 355 | if ((cpustatus & FLAG_SIGN) == FLAG_SIGN) { 356 | oldpc = pc; 357 | pc += reladdr; 358 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 359 | else clockticks6502++; 360 | } 361 | } 362 | 363 | void bne() { 364 | if ((cpustatus & FLAG_ZERO) == 0) { 365 | oldpc = pc; 366 | pc += reladdr; 367 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 368 | else clockticks6502++; 369 | } 370 | } 371 | 372 | void bpl() { 373 | if ((cpustatus & FLAG_SIGN) == 0) { 374 | oldpc = pc; 375 | pc += reladdr; 376 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 377 | else clockticks6502++; 378 | } 379 | } 380 | 381 | void brk() { 382 | pc++; 383 | push16(pc); //push next instruction address onto stack 384 | push8(cpustatus | FLAG_BREAK); //push CPU cpustatus to stack 385 | setinterrupt(); //set interrupt flag 386 | pc = (uint16_t)read6502(0xFFFE) | ((uint16_t)read6502(0xFFFF) << 8); 387 | } 388 | 389 | void bvc() { 390 | if ((cpustatus & FLAG_OVERFLOW) == 0) { 391 | oldpc = pc; 392 | pc += reladdr; 393 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 394 | else clockticks6502++; 395 | } 396 | } 397 | 398 | void bvs() { 399 | if ((cpustatus & FLAG_OVERFLOW) == FLAG_OVERFLOW) { 400 | oldpc = pc; 401 | pc += reladdr; 402 | if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary 403 | else clockticks6502++; 404 | } 405 | } 406 | 407 | void clc() { 408 | clearcarry(); 409 | } 410 | 411 | void cld() { 412 | cleardecimal(); 413 | } 414 | 415 | void cli() { 416 | clearinterrupt(); 417 | } 418 | 419 | void clv() { 420 | clearoverflow(); 421 | } 422 | 423 | void cmp() { 424 | value = getvalue(); 425 | result = (uint16_t)a - value; 426 | 427 | if (a >= (uint8_t)(value & 0x00FF)) setcarry(); 428 | else clearcarry(); 429 | if (a == (uint8_t)(value & 0x00FF)) setzero(); 430 | else clearzero(); 431 | signcalc(result); 432 | } 433 | 434 | void cpx() { 435 | value = getvalue(); 436 | result = (uint16_t)x - value; 437 | 438 | if (x >= (uint8_t)(value & 0x00FF)) setcarry(); 439 | else clearcarry(); 440 | if (x == (uint8_t)(value & 0x00FF)) setzero(); 441 | else clearzero(); 442 | signcalc(result); 443 | } 444 | 445 | void cpy() { 446 | value = getvalue(); 447 | result = (uint16_t)y - value; 448 | 449 | if (y >= (uint8_t)(value & 0x00FF)) setcarry(); 450 | else clearcarry(); 451 | if (y == (uint8_t)(value & 0x00FF)) setzero(); 452 | else clearzero(); 453 | signcalc(result); 454 | } 455 | 456 | void dec() { 457 | value = getvalue(); 458 | result = value - 1; 459 | 460 | zerocalc(result); 461 | signcalc(result); 462 | 463 | putvalue(result); 464 | } 465 | 466 | void dex() { 467 | x--; 468 | 469 | zerocalc(x); 470 | signcalc(x); 471 | } 472 | 473 | void dey() { 474 | y--; 475 | 476 | zerocalc(y); 477 | signcalc(y); 478 | } 479 | 480 | void eor() { 481 | value = getvalue(); 482 | result = (uint16_t)a ^ value; 483 | 484 | zerocalc(result); 485 | signcalc(result); 486 | 487 | saveaccum(result); 488 | } 489 | 490 | void inc() { 491 | value = getvalue(); 492 | result = value + 1; 493 | 494 | zerocalc(result); 495 | signcalc(result); 496 | 497 | putvalue(result); 498 | } 499 | 500 | void inx() { 501 | x++; 502 | 503 | zerocalc(x); 504 | signcalc(x); 505 | } 506 | 507 | void iny() { 508 | y++; 509 | 510 | zerocalc(y); 511 | signcalc(y); 512 | } 513 | 514 | void jmp() { 515 | pc = ea; 516 | } 517 | 518 | void jsr() { 519 | push16(pc - 1); 520 | pc = ea; 521 | } 522 | 523 | void lda() { 524 | value = getvalue(); 525 | a = (uint8_t)(value & 0x00FF); 526 | 527 | zerocalc(a); 528 | signcalc(a); 529 | } 530 | 531 | void ldx() { 532 | value = getvalue(); 533 | x = (uint8_t)(value & 0x00FF); 534 | 535 | zerocalc(x); 536 | signcalc(x); 537 | } 538 | 539 | void ldy() { 540 | value = getvalue(); 541 | y = (uint8_t)(value & 0x00FF); 542 | 543 | zerocalc(y); 544 | signcalc(y); 545 | } 546 | 547 | void lsr() { 548 | value = getvalue(); 549 | result = value >> 1; 550 | 551 | if (value & 1) setcarry(); 552 | else clearcarry(); 553 | zerocalc(result); 554 | signcalc(result); 555 | 556 | putvalue(result); 557 | } 558 | 559 | void nop() { 560 | } 561 | 562 | void ora() { 563 | value = getvalue(); 564 | result = (uint16_t)a | value; 565 | 566 | zerocalc(result); 567 | signcalc(result); 568 | 569 | saveaccum(result); 570 | } 571 | 572 | void pha() { 573 | push8(a); 574 | } 575 | 576 | void php() { 577 | push8(cpustatus | FLAG_BREAK); 578 | } 579 | 580 | void pla() { 581 | a = pull8(); 582 | 583 | zerocalc(a); 584 | signcalc(a); 585 | } 586 | 587 | void plp() { 588 | cpustatus = pull8() | FLAG_CONSTANT; 589 | } 590 | 591 | void rol() { 592 | value = getvalue(); 593 | result = (value << 1) | (cpustatus & FLAG_CARRY); 594 | 595 | carrycalc(result); 596 | zerocalc(result); 597 | signcalc(result); 598 | 599 | putvalue(result); 600 | } 601 | 602 | void ror() { 603 | value = getvalue(); 604 | result = (value >> 1) | ((cpustatus & FLAG_CARRY) << 7); 605 | 606 | if (value & 1) setcarry(); 607 | else clearcarry(); 608 | zerocalc(result); 609 | signcalc(result); 610 | 611 | putvalue(result); 612 | } 613 | 614 | void rti() { 615 | cpustatus = pull8(); 616 | value = pull16(); 617 | pc = value; 618 | } 619 | 620 | void rts() { 621 | value = pull16(); 622 | pc = value + 1; 623 | } 624 | 625 | void sbc() { 626 | value = getvalue() ^ 0x00FF; 627 | result = (uint16_t)a + value + (uint16_t)(cpustatus & FLAG_CARRY); 628 | 629 | carrycalc(result); 630 | zerocalc(result); 631 | overflowcalc(result, a, value); 632 | signcalc(result); 633 | 634 | #ifndef NES_CPU 635 | if (cpustatus & FLAG_DECIMAL) { 636 | clearcarry(); 637 | 638 | a -= 0x66; 639 | if ((a & 0x0F) > 0x09) { 640 | a += 0x06; 641 | } 642 | if ((a & 0xF0) > 0x90) { 643 | a += 0x60; 644 | setcarry(); 645 | } 646 | 647 | clockticks6502++; 648 | } 649 | #endif 650 | 651 | saveaccum(result); 652 | } 653 | 654 | void sec() { 655 | setcarry(); 656 | } 657 | 658 | void sed() { 659 | setdecimal(); 660 | } 661 | 662 | void sei() { 663 | setinterrupt(); 664 | } 665 | 666 | void sta() { 667 | putvalue(a); 668 | } 669 | 670 | void stx() { 671 | putvalue(x); 672 | } 673 | 674 | void sty() { 675 | putvalue(y); 676 | } 677 | 678 | void tax() { 679 | x = a; 680 | 681 | zerocalc(x); 682 | signcalc(x); 683 | } 684 | 685 | void tay() { 686 | y = a; 687 | 688 | zerocalc(y); 689 | signcalc(y); 690 | } 691 | 692 | void tsx() { 693 | x = sp; 694 | 695 | zerocalc(x); 696 | signcalc(x); 697 | } 698 | 699 | void txa() { 700 | a = x; 701 | 702 | zerocalc(a); 703 | signcalc(a); 704 | } 705 | 706 | void txs() { 707 | sp = x; 708 | } 709 | 710 | void tya() { 711 | a = y; 712 | 713 | zerocalc(a); 714 | signcalc(a); 715 | } 716 | 717 | //undocumented instructions 718 | #ifdef UNDOCUMENTED 719 | void lax() { 720 | lda(); 721 | ldx(); 722 | } 723 | 724 | void sax() { 725 | sta(); 726 | stx(); 727 | putvalue(a & x); 728 | } 729 | 730 | void dcp() { 731 | dec(); 732 | cmp(); 733 | } 734 | 735 | void isb() { 736 | inc(); 737 | sbc(); 738 | } 739 | 740 | void slo() { 741 | asl(); 742 | ora(); 743 | } 744 | 745 | void rla() { 746 | rol(); 747 | op_and(); 748 | } 749 | 750 | void sre() { 751 | lsr(); 752 | eor(); 753 | } 754 | 755 | void rra() { 756 | ror(); 757 | adc(); 758 | } 759 | #else 760 | #define lax nop 761 | #define sax nop 762 | #define dcp nop 763 | #define isb nop 764 | #define slo nop 765 | #define rla nop 766 | #define sre nop 767 | #define rra nop 768 | #endif 769 | 770 | 771 | void nmi6502() { 772 | push16(pc); 773 | push8(cpustatus); 774 | cpustatus |= FLAG_INTERRUPT; 775 | pc = (uint16_t)read6502(0xFFFA) | ((uint16_t)read6502(0xFFFB) << 8); 776 | } 777 | 778 | void irq6502() { 779 | //service irq only if FLAG_INTERRUPT is not set 780 | if(!(cpustatus & FLAG_INTERRUPT)) { 781 | push16(pc); 782 | push8(cpustatus); 783 | cpustatus |= FLAG_INTERRUPT; 784 | pc = (uint16_t)read6502(0xFFFE) | ((uint16_t)read6502(0xFFFF) << 8); 785 | } 786 | } 787 | 788 | #ifdef USE_TIMING 789 | prog_char ticktable[256] PROGMEM = { 790 | /* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */ 791 | /* 0 */ 7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, /* 0 */ 792 | /* 1 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 1 */ 793 | /* 2 */ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, /* 2 */ 794 | /* 3 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 3 */ 795 | /* 4 */ 6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6, /* 4 */ 796 | /* 5 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 5 */ 797 | /* 6 */ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6, /* 6 */ 798 | /* 7 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 7 */ 799 | /* 8 */ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* 8 */ 800 | /* 9 */ 2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5, /* 9 */ 801 | /* A */ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* A */ 802 | /* B */ 2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4, /* B */ 803 | /* C */ 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* C */ 804 | /* D */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* D */ 805 | /* E */ 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* E */ 806 | /* F */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7 /* F */ 807 | }; 808 | #endif 809 | 810 | void exec6502(int32_t tickcount) { 811 | #ifdef USE_TIMING 812 | clockgoal6502 += tickcount; 813 | 814 | while (clockgoal6502 > 0) { 815 | #else 816 | while (tickcount--) { 817 | #endif 818 | opcode = read6502(pc++); 819 | cpustatus |= FLAG_CONSTANT; 820 | 821 | useaccum = 0; 822 | 823 | switch (opcode) { 824 | case 0x0: 825 | imp(); 826 | brk(); 827 | break; 828 | case 0x1: 829 | indx(); 830 | ora(); 831 | break; 832 | case 0x5: 833 | zp(); 834 | ora(); 835 | break; 836 | case 0x6: 837 | zp(); 838 | asl(); 839 | break; 840 | case 0x8: 841 | imp(); 842 | php(); 843 | break; 844 | case 0x9: 845 | imm(); 846 | ora(); 847 | break; 848 | case 0xA: 849 | acc(); 850 | asl(); 851 | break; 852 | case 0xD: 853 | abso(); 854 | ora(); 855 | break; 856 | case 0xE: 857 | abso(); 858 | asl(); 859 | break; 860 | case 0x10: 861 | rel(); 862 | bpl(); 863 | break; 864 | case 0x11: 865 | indy(); 866 | ora(); 867 | break; 868 | case 0x15: 869 | zpx(); 870 | ora(); 871 | break; 872 | case 0x16: 873 | zpx(); 874 | asl(); 875 | break; 876 | case 0x18: 877 | imp(); 878 | clc(); 879 | break; 880 | case 0x19: 881 | absy(); 882 | ora(); 883 | break; 884 | case 0x1D: 885 | absx(); 886 | ora(); 887 | break; 888 | case 0x1E: 889 | absx(); 890 | asl(); 891 | break; 892 | case 0x20: 893 | abso(); 894 | jsr(); 895 | break; 896 | case 0x21: 897 | indx(); 898 | op_and(); 899 | break; 900 | case 0x24: 901 | zp(); 902 | op_bit(); 903 | break; 904 | case 0x25: 905 | zp(); 906 | op_and(); 907 | break; 908 | case 0x26: 909 | zp(); 910 | rol(); 911 | break; 912 | case 0x28: 913 | imp(); 914 | plp(); 915 | break; 916 | case 0x29: 917 | imm(); 918 | op_and(); 919 | break; 920 | case 0x2A: 921 | acc(); 922 | rol(); 923 | break; 924 | case 0x2C: 925 | abso(); 926 | op_bit(); 927 | break; 928 | case 0x2D: 929 | abso(); 930 | op_and(); 931 | break; 932 | case 0x2E: 933 | abso(); 934 | rol(); 935 | break; 936 | case 0x30: 937 | rel(); 938 | bmi(); 939 | break; 940 | case 0x31: 941 | indy(); 942 | op_and(); 943 | break; 944 | case 0x35: 945 | zpx(); 946 | op_and(); 947 | break; 948 | case 0x36: 949 | zpx(); 950 | rol(); 951 | break; 952 | case 0x38: 953 | imp(); 954 | sec(); 955 | break; 956 | case 0x39: 957 | absy(); 958 | op_and(); 959 | break; 960 | case 0x3D: 961 | absx(); 962 | op_and(); 963 | break; 964 | case 0x3E: 965 | absx(); 966 | rol(); 967 | break; 968 | case 0x40: 969 | imp(); 970 | rti(); 971 | break; 972 | case 0x41: 973 | indx(); 974 | eor(); 975 | break; 976 | case 0x45: 977 | zp(); 978 | eor(); 979 | break; 980 | case 0x46: 981 | zp(); 982 | lsr(); 983 | break; 984 | case 0x48: 985 | imp(); 986 | pha(); 987 | break; 988 | case 0x49: 989 | imm(); 990 | eor(); 991 | break; 992 | case 0x4A: 993 | acc(); 994 | lsr(); 995 | break; 996 | case 0x4C: 997 | abso(); 998 | jmp(); 999 | break; 1000 | case 0x4D: 1001 | abso(); 1002 | eor(); 1003 | break; 1004 | case 0x4E: 1005 | abso(); 1006 | lsr(); 1007 | break; 1008 | case 0x50: 1009 | rel(); 1010 | bvc(); 1011 | break; 1012 | case 0x51: 1013 | indy(); 1014 | eor(); 1015 | break; 1016 | case 0x55: 1017 | zpx(); 1018 | eor(); 1019 | break; 1020 | case 0x56: 1021 | zpx(); 1022 | lsr(); 1023 | break; 1024 | case 0x58: 1025 | imp(); 1026 | cli(); 1027 | break; 1028 | case 0x59: 1029 | absy(); 1030 | eor(); 1031 | break; 1032 | case 0x5D: 1033 | absx(); 1034 | eor(); 1035 | break; 1036 | case 0x5E: 1037 | absx(); 1038 | lsr(); 1039 | break; 1040 | case 0x60: 1041 | imp(); 1042 | rts(); 1043 | break; 1044 | case 0x61: 1045 | indx(); 1046 | adc(); 1047 | break; 1048 | case 0x65: 1049 | zp(); 1050 | adc(); 1051 | break; 1052 | case 0x66: 1053 | zp(); 1054 | ror(); 1055 | break; 1056 | case 0x68: 1057 | imp(); 1058 | pla(); 1059 | break; 1060 | case 0x69: 1061 | imm(); 1062 | adc(); 1063 | break; 1064 | case 0x6A: 1065 | acc(); 1066 | ror(); 1067 | break; 1068 | case 0x6C: 1069 | ind(); 1070 | jmp(); 1071 | break; 1072 | case 0x6D: 1073 | abso(); 1074 | adc(); 1075 | break; 1076 | case 0x6E: 1077 | abso(); 1078 | ror(); 1079 | break; 1080 | case 0x70: 1081 | rel(); 1082 | bvs(); 1083 | break; 1084 | case 0x71: 1085 | indy(); 1086 | adc(); 1087 | break; 1088 | case 0x75: 1089 | zpx(); 1090 | adc(); 1091 | break; 1092 | case 0x76: 1093 | zpx(); 1094 | ror(); 1095 | break; 1096 | case 0x78: 1097 | imp(); 1098 | sei(); 1099 | break; 1100 | case 0x79: 1101 | absy(); 1102 | adc(); 1103 | break; 1104 | case 0x7D: 1105 | absx(); 1106 | adc(); 1107 | break; 1108 | case 0x7E: 1109 | absx(); 1110 | ror(); 1111 | break; 1112 | case 0x81: 1113 | indx(); 1114 | sta(); 1115 | break; 1116 | case 0x84: 1117 | zp(); 1118 | sty(); 1119 | break; 1120 | case 0x85: 1121 | zp(); 1122 | sta(); 1123 | break; 1124 | case 0x86: 1125 | zp(); 1126 | stx(); 1127 | break; 1128 | case 0x88: 1129 | imp(); 1130 | dey(); 1131 | break; 1132 | case 0x8A: 1133 | imp(); 1134 | txa(); 1135 | break; 1136 | case 0x8C: 1137 | abso(); 1138 | sty(); 1139 | break; 1140 | case 0x8D: 1141 | abso(); 1142 | sta(); 1143 | break; 1144 | case 0x8E: 1145 | abso(); 1146 | stx(); 1147 | break; 1148 | case 0x90: 1149 | rel(); 1150 | bcc(); 1151 | break; 1152 | case 0x91: 1153 | indy(); 1154 | sta(); 1155 | break; 1156 | case 0x94: 1157 | zpx(); 1158 | sty(); 1159 | break; 1160 | case 0x95: 1161 | zpx(); 1162 | sta(); 1163 | break; 1164 | case 0x96: 1165 | zpy(); 1166 | stx(); 1167 | break; 1168 | case 0x98: 1169 | imp(); 1170 | tya(); 1171 | break; 1172 | case 0x99: 1173 | absy(); 1174 | sta(); 1175 | break; 1176 | case 0x9A: 1177 | imp(); 1178 | txs(); 1179 | break; 1180 | case 0x9D: 1181 | absx(); 1182 | sta(); 1183 | break; 1184 | case 0xA0: 1185 | imm(); 1186 | ldy(); 1187 | break; 1188 | case 0xA1: 1189 | indx(); 1190 | lda(); 1191 | break; 1192 | case 0xA2: 1193 | imm(); 1194 | ldx(); 1195 | break; 1196 | case 0xA4: 1197 | zp(); 1198 | ldy(); 1199 | break; 1200 | case 0xA5: 1201 | zp(); 1202 | lda(); 1203 | break; 1204 | case 0xA6: 1205 | zp(); 1206 | ldx(); 1207 | break; 1208 | case 0xA8: 1209 | imp(); 1210 | tay(); 1211 | break; 1212 | case 0xA9: 1213 | imm(); 1214 | lda(); 1215 | break; 1216 | case 0xAA: 1217 | imp(); 1218 | tax(); 1219 | break; 1220 | case 0xAC: 1221 | abso(); 1222 | ldy(); 1223 | break; 1224 | case 0xAD: 1225 | abso(); 1226 | lda(); 1227 | break; 1228 | case 0xAE: 1229 | abso(); 1230 | ldx(); 1231 | break; 1232 | case 0xB0: 1233 | rel(); 1234 | bcs(); 1235 | break; 1236 | case 0xB1: 1237 | indy(); 1238 | lda(); 1239 | break; 1240 | case 0xB4: 1241 | zpx(); 1242 | ldy(); 1243 | break; 1244 | case 0xB5: 1245 | zpx(); 1246 | lda(); 1247 | break; 1248 | case 0xB6: 1249 | zpy(); 1250 | ldx(); 1251 | break; 1252 | case 0xB8: 1253 | imp(); 1254 | clv(); 1255 | break; 1256 | case 0xB9: 1257 | absy(); 1258 | lda(); 1259 | break; 1260 | case 0xBA: 1261 | imp(); 1262 | tsx(); 1263 | break; 1264 | case 0xBC: 1265 | absx(); 1266 | ldy(); 1267 | break; 1268 | case 0xBD: 1269 | absx(); 1270 | lda(); 1271 | break; 1272 | case 0xBE: 1273 | absy(); 1274 | ldx(); 1275 | break; 1276 | case 0xC0: 1277 | imm(); 1278 | cpy(); 1279 | break; 1280 | case 0xC1: 1281 | indx(); 1282 | cmp(); 1283 | break; 1284 | case 0xC4: 1285 | zp(); 1286 | cpy(); 1287 | break; 1288 | case 0xC5: 1289 | zp(); 1290 | cmp(); 1291 | break; 1292 | case 0xC6: 1293 | zp(); 1294 | dec(); 1295 | break; 1296 | case 0xC8: 1297 | imp(); 1298 | iny(); 1299 | break; 1300 | case 0xC9: 1301 | imm(); 1302 | cmp(); 1303 | break; 1304 | case 0xCA: 1305 | imp(); 1306 | dex(); 1307 | break; 1308 | case 0xCC: 1309 | abso(); 1310 | cpy(); 1311 | break; 1312 | case 0xCD: 1313 | abso(); 1314 | cmp(); 1315 | break; 1316 | case 0xCE: 1317 | abso(); 1318 | dec(); 1319 | break; 1320 | case 0xD0: 1321 | rel(); 1322 | bne(); 1323 | break; 1324 | case 0xD1: 1325 | indy(); 1326 | cmp(); 1327 | break; 1328 | case 0xD5: 1329 | zpx(); 1330 | cmp(); 1331 | break; 1332 | case 0xD6: 1333 | zpx(); 1334 | dec(); 1335 | break; 1336 | case 0xD8: 1337 | imp(); 1338 | cld(); 1339 | break; 1340 | case 0xD9: 1341 | absy(); 1342 | cmp(); 1343 | break; 1344 | case 0xDD: 1345 | absx(); 1346 | cmp(); 1347 | break; 1348 | case 0xDE: 1349 | absx(); 1350 | dec(); 1351 | break; 1352 | case 0xE0: 1353 | imm(); 1354 | cpx(); 1355 | break; 1356 | case 0xE1: 1357 | indx(); 1358 | sbc(); 1359 | break; 1360 | case 0xE4: 1361 | zp(); 1362 | cpx(); 1363 | break; 1364 | case 0xE5: 1365 | zp(); 1366 | sbc(); 1367 | break; 1368 | case 0xE6: 1369 | zp(); 1370 | inc(); 1371 | break; 1372 | case 0xE8: 1373 | imp(); 1374 | inx(); 1375 | break; 1376 | case 0xE9: 1377 | imm(); 1378 | sbc(); 1379 | break; 1380 | case 0xEB: 1381 | imm(); 1382 | sbc(); 1383 | break; 1384 | case 0xEC: 1385 | abso(); 1386 | cpx(); 1387 | break; 1388 | case 0xED: 1389 | abso(); 1390 | sbc(); 1391 | break; 1392 | case 0xEE: 1393 | abso(); 1394 | inc(); 1395 | break; 1396 | case 0xF0: 1397 | rel(); 1398 | beq(); 1399 | break; 1400 | case 0xF1: 1401 | indy(); 1402 | sbc(); 1403 | break; 1404 | case 0xF5: 1405 | zpx(); 1406 | sbc(); 1407 | break; 1408 | case 0xF6: 1409 | zpx(); 1410 | inc(); 1411 | break; 1412 | case 0xF8: 1413 | imp(); 1414 | sed(); 1415 | break; 1416 | case 0xF9: 1417 | absy(); 1418 | sbc(); 1419 | break; 1420 | case 0xFD: 1421 | absx(); 1422 | sbc(); 1423 | break; 1424 | case 0xFE: 1425 | absx(); 1426 | inc(); 1427 | break; 1428 | } 1429 | #ifdef USE_TIMING 1430 | clockgoal6502 -= (int32_t)pgm_read_byte_near(ticktable + opcode); 1431 | #endif 1432 | instructions++; 1433 | } 1434 | } 1435 | 1436 | uint16_t getpc() { 1437 | return(pc); 1438 | } 1439 | 1440 | uint8_t getop() { 1441 | return(opcode); 1442 | } 1443 | 1444 | -------------------------------------------------------------------------------- /M-OS-6502/SW_disassembler.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; 6502/65C02 Disassembler 3 | ; 4 | ; Copyright (C) 2012 by Jeff Tranter 5 | ; 6 | ; Licensed under the Apache License, Version 2.0 (the "License"); 7 | ; you may not use this file except in compliance with the License. 8 | ; You may obtain a copy of the License at 9 | ; 10 | ; http://www.apache.org/licenses/LICENSE-2.0 11 | ; 12 | ; Unless required by applicable law or agreed to in writing, software 13 | ; distributed under the License is distributed on an "AS IS" BASIS, 14 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | ; See the License for the specific language governing permissions and 16 | ; limitations under the License. 17 | ; 18 | ; Revision History 19 | ; Version Date Comments 20 | ; 0.0 25-Mar-2012 First version started 21 | ; 0.9 28-Mar-2012 First public beta version 22 | 23 | ; *** ASSEMBLY TIME OPTIONS *** 24 | 25 | ; Uncomment this if you don't want instructions that operate on the 26 | ; accumulator like ASL to be shown as "ASL A" but instead just "ASL". 27 | ; NOACCUMULATOR = 1 28 | 29 | ; Uncomment this if you want the output to include source code only 30 | ; and not the data bytes in memory. This allows the output to be fed 31 | ; back to an assembler. 32 | ; SOURCEONLY = 1 33 | 34 | ; Uncomment next line to link with start address of $A000 for Multi I/0 Board EEPROM. 35 | ; .org $A000 36 | 37 | 38 | ; 39 | ; py65 Hack 40 | ; $f001 and $f004 are used for character I/O 41 | ; 42 | .advance $f005 43 | 44 | ; *** CONSTANTS *** 45 | 46 | ; Characters 47 | .alias CR LINE_END ; Carriage Return 48 | .alias SP $20 ; Space 49 | .alias ESC $1B ; Escape 50 | 51 | ; External Routines 52 | ;.alias ECHO $FFEF ; Woz monitor ECHO routine 53 | ;.alias PRBYTE $FFDC ; Woz monitor print byte as two hex chars 54 | ;.alias PRHEX $FFE5 ; Woz monitor print nybble as hex digit 55 | 56 | ; Instructions. Matches entries in table of MNEMONICS 57 | .alias OP_INV $00 58 | .alias OP_ADC $01 59 | .alias OP_AND $02 60 | .alias OP_ASL $03 61 | .alias OP_BCC $04 62 | .alias OP_BCS $05 63 | .alias OP_BEQ $06 64 | .alias OP_BIT $07 65 | .alias OP_BMI $08 66 | .alias OP_BNE $09 67 | .alias OP_BPL $0A 68 | .alias OP_BRK $0B 69 | .alias OP_BVC $0C 70 | .alias OP_BVS $0D 71 | .alias OP_CLC $0E 72 | .alias OP_CLD $0F 73 | .alias OP_CLI $10 74 | .alias OP_CLV $11 75 | .alias OP_CMP $12 76 | .alias OP_CPX $13 77 | .alias OP_CPY $14 78 | .alias OP_DEC $15 79 | .alias OP_DEX $16 80 | .alias OP_DEY $17 81 | .alias OP_EOR $18 82 | .alias OP_INC $19 83 | .alias OP_INX $1A 84 | .alias OP_INY $1B 85 | .alias OP_JMP $1C 86 | .alias OP_JSR $1D 87 | .alias OP_LDA $1E 88 | .alias OP_LDX $1F 89 | .alias OP_LDY $20 90 | .alias OP_LSR $21 91 | .alias OP_NOP $22 92 | .alias OP_ORA $23 93 | .alias OP_PHA $24 94 | .alias OP_PHP $25 95 | .alias OP_PLA $26 96 | .alias OP_PLP $27 97 | .alias OP_ROL $28 98 | .alias OP_ROR $29 99 | .alias OP_RTI $2A 100 | .alias OP_RTS $2B 101 | .alias OP_SBC $2C 102 | .alias OP_SEC $2D 103 | .alias OP_SED $2E 104 | .alias OP_SEI $2F 105 | .alias OP_STA $30 106 | .alias OP_STX $31 107 | .alias OP_STY $32 108 | .alias OP_TAX $33 109 | .alias OP_TAY $34 110 | .alias OP_TSX $35 111 | .alias OP_TXA $36 112 | .alias OP_TXS $37 113 | .alias OP_TYA $38 114 | .alias OP_BBR $39 ; [65C02 only] 115 | .alias OP_BBS $3A ; [65C02 only] 116 | .alias OP_BRA $3B ; [65C02 only] 117 | .alias OP_PHX $3C ; [65C02 only] 118 | .alias OP_PHY $3D ; [65C02 only] 119 | .alias OP_PLX $3E ; [65C02 only] 120 | .alias OP_PLY $3F ; [65C02 only] 121 | .alias OP_RMB $40 ; [65C02 only] 122 | .alias OP_SMB $41 ; [65C02 only] 123 | .alias OP_STZ $42 ; [65C02 only] 124 | .alias OP_TRB $43 ; [65C02 only] 125 | .alias OP_TSB $44 ; [65C02 only] 126 | .alias OP_STP $45 ; [WDC 65C02 only] 127 | .alias OP_WAI $46 ; [WDC 65C02 only] 128 | 129 | ; Addressing Modes. OPCODES1/OPCODES2 tables list these for each instruction. LENGTHS lists the instruction length for each addressing mode. 130 | .alias AM_INVALID 0 ; example: 131 | .alias AM_IMPLICIT 1 ; RTS 132 | .alias AM_ACCUMULATOR 2 ; ASL A 133 | .alias AM_IMMEDIATE 3 ; LDA #$12 134 | .alias AM_ZEROPAGE 4 ; LDA $12 135 | .alias AM_ZEROPAGE_X 5 ; LDA $12,X 136 | .alias AM_ZEROPAGE_Y 6 ; LDA $12,Y 137 | .alias AM_RELATIVE 7 ; BNE $FD 138 | .alias AM_ABSOLUTE 8 ; JSR $1234 139 | .alias AM_ABSOLUTE_X 9 ; STA $1234,X 140 | .alias AM_ABSOLUTE_Y 10 ; STA $1234,Y 141 | .alias AM_INDIRECT 11 ; JMP ($1234) 142 | .alias AM_INDEXED_INDIRECT 12 ; LDA ($12,X) 143 | .alias AM_INDIRECT_INDEXED 13 ; LDA ($12),Y 144 | .alias AM_INDIRECT_ZEROPAGE 14 ; LDA ($12) [65C02 only] 145 | .alias AM_ABSOLUTE_INDEXED_INDIRECT 15 ; JMP ($1234,X) [65C02 only] 146 | 147 | ; *** VARIABLES *** 148 | 149 | ; Page zero variables 150 | .alias T1 $35 ; temp variable 1 151 | .alias T2 $36 ; temp variable 2 152 | ;.alias ADDR $37 ; instruction address, 2 bytes (low/high) 153 | .alias OPCODE $39 ; instruction opcode 154 | .alias OP $3A ; instruction type OP_* 155 | .alias AM $41 ; addressing mode AM_* 156 | .alias LEN $42 ; instruction length 157 | .alias REL $43 ; relative addressing branch offset (2 bytes) 158 | .alias DEST $45 ; relative address destination address (2 bytes) 159 | 160 | ; *** CODE *** 161 | 162 | ; Main program disassembles starting from itself. Prompts user to hit 163 | ; key to continue after each screen. 164 | DSTART: 165 | OUTER: 166 | .invoke linefeed 167 | LDA #23 168 | DLOOP: 169 | PHA 170 | JSR DISASM 171 | PLA 172 | SEC 173 | SBC #1 174 | BNE DLOOP 175 | .invoke print ContinueString 176 | SpaceOrEscape: 177 | JSR j_rchr 178 | CMP #$20 179 | BEQ OUTER 180 | CMP #$1B 181 | BNE SpaceOrEscape 182 | JMP m_parse_end 183 | 184 | ; Disassemble instruction at address K_VAR1_L (low) / K_VAR1_H (high). On 185 | ; return K_VAR1_L/K_VAR1_H points to next instruction so it can be called 186 | ; again. 187 | DISASM: 188 | LDX #0 189 | LDA (K_VAR1_L,X) ; get instruction op code 190 | STA OPCODE 191 | BMI UPPER ; if bit 7 set, in upper half of table 192 | ASL ; double it since table is two bytes per entry 193 | TAX 194 | LDA OPCODES1,X ; get the instruction type (e.g. OP_LDA) 195 | STA OP ; store it 196 | INX 197 | LDA OPCODES1,X ; get addressing mode 198 | STA AM ; store it 199 | JMP AROUND 200 | UPPER: 201 | ASL ; double it since table is two bytes per entry 202 | TAX 203 | LDA OPCODES2,X ; get the instruction type (e.g. OP_LDA) 204 | STA OP ; store it 205 | INX 206 | LDA OPCODES2,X ; get addressing mode 207 | STA AM ; store it 208 | AROUND: 209 | TAX ; put addressing mode in X 210 | LDA LENGTHS,X ; get instruction length given addressing mode 211 | STA LEN ; store it 212 | LDX K_VAR1_L 213 | LDY K_VAR1_H 214 | ; .ifndef SOURCEONLY 215 | JSR PrintDollar 216 | JSR PrintAddress ; print address 217 | LDX #3 218 | JSR PrintSpaces ; then three spaces 219 | LDA OPCODE ; get instruction op code 220 | JSR PrintDollar 221 | JSR PrintByte ; display the opcode byte 222 | JSR PrintSpace 223 | LDA LEN ; how many bytes in the instruction? 224 | CMP #3 225 | BEQ THREE 226 | CMP #2 227 | BEQ TWO 228 | LDX #7 229 | JSR PrintSpaces 230 | JMP ONE 231 | TWO: 232 | LDY #1 233 | LDA (K_VAR1_L),Y ; get 1st operand byte 234 | JSR PrintDollar 235 | JSR PrintByte ; display it 236 | LDX #4 237 | JSR PrintSpaces 238 | JMP ONE 239 | THREE: 240 | LDY #1 241 | LDA (K_VAR1_L),Y ; get 1st operand byte 242 | JSR PrintDollar 243 | JSR PrintByte ; display it 244 | JSR PrintSpace 245 | LDY #2 246 | LDA (K_VAR1_L),Y ; get 2nd operand byte 247 | JSR PrintDollar 248 | JSR PrintByte ; display it 249 | ONE: 250 | ; .endif ; .ifndef SOURCEONLY 251 | LDX #4 252 | JSR PrintSpaces 253 | LDA OP ; get the op code 254 | ASL ; multiply by 2 255 | CLC 256 | ADC OP ; add one more to multiply by 3 since table is three bytes per entry 257 | TAX 258 | LDY #3 259 | MNEM: 260 | LDA MNEMONICS,X ; print three chars of mnemonic 261 | JSR j_wchr 262 | INX 263 | DEY 264 | BNE MNEM 265 | ; Display any operands based on addressing mode 266 | LDA OP ; is it RMB or SMB? 267 | CMP #OP_RMB 268 | BEQ DOMB 269 | CMP #OP_SMB 270 | BNE TRYBB 271 | DOMB: 272 | LDA OPCODE ; get the op code 273 | AND #$70 ; Upper 3 bits is the bit number 274 | LSR 275 | LSR 276 | LSR 277 | LSR 278 | JSR j_hex8out 279 | LDX #2 280 | JSR PrintSpaces 281 | JSR PrintDollar 282 | LDY #1 283 | LDA (K_VAR1_L),Y ; get 1st operand byte (low address) 284 | JSR PrintByte ; display it 285 | JMP DONEOPS 286 | TRYBB: 287 | LDA OP ; is it BBR or BBS? 288 | CMP #OP_BBR 289 | BEQ DOBB 290 | CMP #OP_BBS 291 | BNE TRYIMP 292 | DOBB: ; handle special BBRn and BBSn instructions 293 | LDA OPCODE ; get the op code 294 | AND #$70 ; Upper 3 bits is the bit number 295 | LSR 296 | LSR 297 | LSR 298 | LSR 299 | JSR j_hex8out 300 | LDX #2 301 | JSR PrintSpaces 302 | JSR PrintDollar 303 | LDY #1 304 | LDA (K_VAR1_L),Y ; get 1st operand byte (address) 305 | JSR PrintByte ; display it 306 | LDA #$2C 307 | JSR j_wchr 308 | JSR PrintDollar 309 | ; Handle relative addressing 310 | ; Destination address is Current address + relative (sign extended so upper byte is $00 or $FF) + 3 311 | LDY #2 312 | LDA (K_VAR1_L),Y ; get 2nd operand byte (relative branch offset) 313 | STA REL ; save low byte of offset 314 | BMI _DNEG ; if negative, need to sign extend 315 | LDA #0 ; high byte is zero 316 | BEQ _DADD 317 | _DNEG: 318 | LDA #$FF ; negative offset, high byte if $FF 319 | _DADD: 320 | STA REL+1 ; save offset high byte 321 | LDA K_VAR1_L ; take adresss 322 | CLC 323 | ADC REL ; add offset 324 | STA DEST ; and store 325 | LDA K_VAR1_H ; also high byte (including carry) 326 | ADC REL+1 327 | STA DEST+1 328 | LDA DEST ; now need to add 3 more to the address 329 | CLC 330 | ADC #3 331 | STA DEST 332 | LDA DEST+1 333 | ADC #0 ; add any carry 334 | STA DEST+1 335 | JSR PrintByte ; display high byte 336 | LDA DEST 337 | JSR PrintByte ; display low byte 338 | JMP DONEOPS 339 | TRYIMP: 340 | LDA AM 341 | CMP #AM_IMPLICIT 342 | BNE TRYINV 343 | JMP DONEOPS ; no operands 344 | TRYINV: 345 | CMP #AM_INVALID 346 | BNE TRYACC 347 | JMP DONEOPS ; no operands 348 | TRYACC: 349 | LDX #3 350 | JSR PrintSpaces 351 | CMP #AM_ACCUMULATOR 352 | BNE TRYIMM 353 | ; .ifndef NOACCUMULATOR 354 | LDA #'A 355 | JSR j_wchr 356 | ; .endif ; .ifndef NOACCUMULATOR 357 | JMP DONEOPS 358 | TRYIMM: 359 | CMP #AM_IMMEDIATE 360 | BNE TRYZP 361 | LDA #$23 362 | JSR j_wchr 363 | JSR PrintDollar 364 | LDY #1 365 | LDA (K_VAR1_L),Y ; get 1st operand byte (low address) 366 | JSR PrintByte ; display it 367 | JMP DONEOPS 368 | TRYZP: 369 | CMP #AM_ZEROPAGE 370 | BNE TRYZPX 371 | JSR PrintDollar 372 | LDY #1 373 | LDA (K_VAR1_L),Y ; get 1st operand byte (low address) 374 | JSR PrintByte ; display it 375 | JMP DONEOPS 376 | TRYZPX: 377 | CMP #AM_ZEROPAGE_X 378 | BNE TRYZPY 379 | LDY #1 380 | LDA (K_VAR1_L),Y ; get 1st operand byte (address) 381 | JSR PrintDollar 382 | JSR PrintByte ; display it 383 | JSR PrintCommaX 384 | JMP DONEOPS 385 | TRYZPY: 386 | CMP #AM_ZEROPAGE_Y 387 | BNE TRYREL 388 | LDY #1 389 | LDA (K_VAR1_L),Y ; get 1st operand byte (address) 390 | JSR PrintDollar 391 | JSR PrintByte ; display it 392 | JSR PrintCommaY 393 | JMP DONEOPS 394 | TRYREL: 395 | CMP #AM_RELATIVE 396 | BNE TRYABS 397 | JSR PrintDollar 398 | ; Handle relative addressing 399 | ; Destination address is Current address + relative (sign extended so upper byte is $00 or $FF) + 2 400 | LDY #1 401 | LDA (K_VAR1_L),Y ; get 1st operand byte (relative branch offset) 402 | STA REL ; save low byte of offset 403 | BMI NEG ; if negative, need to sign extend 404 | LDA #0 ; high byte is zero 405 | BEQ DADD 406 | NEG: 407 | LDA #$FF ; negative offset, high byte if $FF 408 | DADD: 409 | STA REL+1 ; save offset high byte 410 | LDA K_VAR1_L ; take adresss 411 | CLC 412 | ADC REL ; add offset 413 | STA DEST ; and store 414 | LDA K_VAR1_H ; also high byte (including carry) 415 | ADC REL+1 416 | STA DEST+1 417 | LDA DEST ; now need to add 2 more to the address 418 | CLC 419 | ADC #2 420 | STA DEST 421 | LDA DEST+1 422 | ADC #0 ; add any carry 423 | STA DEST+1 424 | JSR PrintByte ; display high byte 425 | LDA DEST 426 | JSR PrintByte ; display low byte 427 | JMP DONEOPS 428 | TRYABS: 429 | CMP #AM_ABSOLUTE 430 | BNE TRYABSX 431 | JSR PrintDollar 432 | LDY #2 433 | LDA (K_VAR1_L),Y ; get 2nd operand byte (high address) 434 | JSR PrintByte ; display it 435 | LDY #1 436 | LDA (K_VAR1_L),Y ; get 1st operand byte (low address) 437 | JSR PrintByte ; display it 438 | JMP DONEOPS 439 | TRYABSX: 440 | CMP #AM_ABSOLUTE_X 441 | BNE TRYABSY 442 | JSR PrintDollar 443 | LDY #2 444 | LDA (K_VAR1_L),Y ; get 2nd operand byte (high address) 445 | JSR PrintByte ; display it 446 | LDY #1 447 | LDA (K_VAR1_L),Y ; get 1st operand byte (low address) 448 | JSR PrintByte ; display it 449 | JSR PrintCommaX 450 | JMP DONEOPS 451 | TRYABSY: 452 | CMP #AM_ABSOLUTE_Y 453 | BNE TRYIND 454 | JSR PrintDollar 455 | LDY #2 456 | LDA (K_VAR1_L),Y ; get 2nd operand byte (high address) 457 | JSR PrintByte ; display it 458 | LDY #1 459 | LDA (K_VAR1_L),Y ; get 1st operand byte (low address) 460 | JSR PrintByte ; display it 461 | JSR PrintCommaY 462 | JMP DONEOPS 463 | TRYIND: 464 | CMP #AM_INDIRECT 465 | BNE TRYINDXIND 466 | JSR PrintLParenDollar 467 | LDY #2 468 | LDA (K_VAR1_L),Y ; get 2nd operand byte (high address) 469 | JSR PrintByte ; display it 470 | LDY #1 471 | LDA (K_VAR1_L),Y ; get 1st operand byte (low address) 472 | JSR PrintByte ; display it 473 | JSR PrintRParen 474 | JMP DONEOPS 475 | TRYINDXIND: 476 | CMP #AM_INDEXED_INDIRECT 477 | BNE TRYINDINDX 478 | JSR PrintLParenDollar 479 | LDY #1 480 | LDA (K_VAR1_L),Y ; get 1st operand byte (low address) 481 | JSR PrintByte ; display it 482 | JSR PrintCommaX 483 | JSR PrintRParen 484 | JMP DONEOPS 485 | TRYINDINDX: 486 | CMP #AM_INDIRECT_INDEXED 487 | BNE TRYINDZ 488 | JSR PrintLParenDollar 489 | LDY #1 490 | LDA (K_VAR1_L),Y ; get 1st operand byte (low address) 491 | JSR PrintByte ; display it 492 | JSR PrintRParen 493 | JSR PrintCommaY 494 | JMP DONEOPS 495 | TRYINDZ: 496 | CMP #AM_INDIRECT_ZEROPAGE ; [65C02 only] 497 | BNE TRYABINDIND 498 | JSR PrintLParenDollar 499 | LDY #1 500 | LDA (K_VAR1_L),Y ; get 1st operand byte (low address) 501 | JSR PrintByte ; display it 502 | JSR PrintRParen 503 | JMP DONEOPS 504 | TRYABINDIND: 505 | CMP #AM_ABSOLUTE_INDEXED_INDIRECT ; [65C02 only] 506 | BNE DONEOPS 507 | JSR PrintLParenDollar 508 | LDY #2 509 | LDA (K_VAR1_L),Y ; get 2nd operand byte (high address) 510 | JSR PrintByte ; display it 511 | LDY #1 512 | LDA (K_VAR1_L),Y ; get 1st operand byte (low address) 513 | JSR PrintByte ; display it 514 | JSR PrintCommaX 515 | JSR PrintRParen 516 | JMP DONEOPS 517 | DONEOPS: 518 | .invoke linefeed ; print a final CR 519 | LDA K_VAR1_L ; update address to next instruction 520 | CLC 521 | ADC LEN 522 | STA K_VAR1_L 523 | LDA K_VAR1_H 524 | ADC #0 ; to add carry 525 | STA K_VAR1_H 526 | RTS 527 | 528 | ;------------------------------------------------------------------------ 529 | ; Utility functions 530 | 531 | ; Print a dollar sign 532 | ; Registers changed: None 533 | PrintDollar: 534 | PHA 535 | LDA #$24 536 | JSR j_wchr 537 | PLA 538 | RTS 539 | 540 | ; Print ",X" 541 | ; Registers changed: None 542 | PrintCommaX: 543 | PHA 544 | LDA #$2C 545 | JSR j_wchr 546 | LDA #'X 547 | JSR j_wchr 548 | PLA 549 | RTS 550 | 551 | ; Print ",Y" 552 | ; Registers changed: None 553 | PrintCommaY: 554 | PHA 555 | LDA #$2C 556 | JSR j_wchr 557 | LDA #'Y 558 | JSR j_wchr 559 | PLA 560 | RTS 561 | 562 | ; Print "($" 563 | ; Registers changed: None 564 | PrintLParenDollar: 565 | PHA 566 | LDA #$28 567 | JSR j_wchr 568 | LDA #$24 569 | JSR j_wchr 570 | PLA 571 | RTS 572 | 573 | ; Print a right parenthesis 574 | ; Registers changed: None 575 | PrintRParen: 576 | PHA 577 | LDA #$29 578 | JSR j_wchr 579 | PLA 580 | RTS 581 | 582 | ; Print a carriage return 583 | ; Registers changed: None 584 | PrintCR: 585 | PHA 586 | LDA #CR 587 | JSR j_wchr 588 | PLA 589 | RTS 590 | 591 | ; Print a space 592 | ; Registers changed: None 593 | PrintSpace: 594 | PHA 595 | LDA #SP 596 | JSR j_wchr 597 | PLA 598 | RTS 599 | 600 | ; Print number of spaces in X 601 | ; Registers changed: X 602 | PrintSpaces: 603 | PHA 604 | LDA #SP 605 | * JSR j_wchr 606 | DEX 607 | BNE - 608 | PLA 609 | RTS 610 | 611 | ; Get character from keyboard 612 | ; Returns in A 613 | ; Clears high bit to be valid ASCII 614 | ; Registers changed: A 615 | GetKey: 616 | jsr j_rchr ; read character 617 | bcs GetKey ; wait for character 618 | AND #%01111111 619 | RTS 620 | 621 | ; Print 16-bit address in hex 622 | ; Pass byte in X (low) and Y (high) 623 | ; Registers changed: None 624 | PrintAddress: 625 | PHA 626 | lda K_VAR1_H 627 | JSR j_hex8out 628 | lda K_VAR1_L 629 | JSR j_hex8out 630 | PLA 631 | RTS 632 | 633 | ; Print byte in hex 634 | ; Pass byte in A 635 | ; Registers changed: None 636 | PrintByte: 637 | pha 638 | JSR j_hex8out 639 | pla 640 | RTS 641 | 642 | ; get opcode 643 | ; get mnemonic, addressing mode, instruction length 644 | ; display opcode string 645 | ; display arguments based on addressing mode 646 | ; increment instruction pointer based on instruction length 647 | ; loop back 648 | 649 | ; DATA 650 | 651 | ; Table of instruction strings. 3 bytes per table entry 652 | ; .export MNEMONICS 653 | MNEMONICS: 654 | .byte "???" ; $00 655 | .byte "ADC" ; $01 656 | .byte "AND" ; $02 657 | .byte "ASL" ; $03 658 | .byte "BCC" ; $04 659 | .byte "BCS" ; $05 660 | .byte "BEQ" ; $06 661 | .byte "BIT" ; $07 662 | .byte "BMI" ; $08 663 | .byte "BNE" ; $09 664 | .byte "BPL" ; $0A 665 | .byte "BRK" ; $0B 666 | .byte "BVC" ; $0C 667 | .byte "BVS" ; $0D 668 | .byte "CLC" ; $0E 669 | .byte "CLD" ; $0F 670 | .byte "CLI" ; $10 671 | .byte "CLV" ; $11 672 | .byte "CMP" ; $12 673 | .byte "CPX" ; $13 674 | .byte "CPY" ; $14 675 | .byte "DEC" ; $15 676 | .byte "DEX" ; $16 677 | .byte "DEY" ; $17 678 | .byte "EOR" ; $18 679 | .byte "INC" ; $19 680 | .byte "INX" ; $1A 681 | .byte "INY" ; $1B 682 | .byte "JMP" ; $1C 683 | .byte "JSR" ; $1D 684 | .byte "LDA" ; $1E 685 | .byte "LDX" ; $1F 686 | .byte "LDY" ; $20 687 | .byte "LSR" ; $21 688 | .byte "NOP" ; $22 689 | .byte "ORA" ; $23 690 | .byte "PHA" ; $24 691 | .byte "PHP" ; $25 692 | .byte "PLA" ; $26 693 | .byte "PLP" ; $27 694 | .byte "ROL" ; $28 695 | .byte "ROR" ; $29 696 | .byte "RTI" ; $2A 697 | .byte "RTS" ; $2B 698 | .byte "SBC" ; $2C 699 | .byte "SEC" ; $2D 700 | .byte "SED" ; $2E 701 | .byte "SEI" ; $2F 702 | .byte "STA" ; $30 703 | .byte "STX" ; $31 704 | .byte "STY" ; $32 705 | .byte "TAX" ; $33 706 | .byte "TAY" ; $34 707 | .byte "TSX" ; $35 708 | .byte "TXA" ; $36 709 | .byte "TXS" ; $37 710 | .byte "TYA" ; $38 711 | .byte "BBR" ; $39 [65C02 only] 712 | .byte "BBS" ; $3A [65C02 only] 713 | .byte "BRA" ; $3B [65C02 only] 714 | .byte "PHX" ; $3C [65C02 only] 715 | .byte "PHY" ; $3D [65C02 only] 716 | .byte "PLX" ; $3E [65C02 only] 717 | .byte "PLY" ; $3F [65C02 only] 718 | .byte "RMB" ; $40 [65C02 only] 719 | .byte "SMB" ; $41 [65C02 only] 720 | .byte "STZ" ; $42 [65C02 only] 721 | .byte "TRB" ; $43 [65C02 only] 722 | .byte "TSB" ; $44 [65C02 only] 723 | .byte "STP" ; $45 [WDC 65C02 only] 724 | .byte "WAI" ; $46 [WDC 65C02 only] 725 | MNEMONICSEND: 726 | 727 | ; Lengths of instructions given an addressing mode. Matches values of AM_* 728 | LENGTHS: 729 | .byte 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 3 730 | 731 | ; Opcodes. Listed in order. Defines the mnemonic and addressing mode. 732 | ; 2 bytes per table entry 733 | ; .export OPCODES1 734 | OPCODES: 735 | OPCODES1: 736 | .byte OP_BRK, AM_IMPLICIT ; $00 737 | .byte OP_ORA, AM_INDEXED_INDIRECT ; $01 738 | .byte OP_INV, AM_INVALID ; $02 739 | .byte OP_INV, AM_INVALID ; $03 740 | .byte OP_TSB, AM_ZEROPAGE ; $04 [65C02 only] 741 | .byte OP_ORA, AM_ZEROPAGE ; $05 742 | .byte OP_ASL, AM_ZEROPAGE ; $06 743 | .byte OP_RMB, AM_ZEROPAGE ; $07 [65C02 only] 744 | .byte OP_PHP, AM_IMPLICIT ; $08 745 | .byte OP_ORA, AM_IMMEDIATE ; $09 746 | .byte OP_ASL, AM_ACCUMULATOR ; $0A 747 | .byte OP_INV, AM_INVALID ; $0B 748 | .byte OP_TSB, AM_ABSOLUTE ; $0C [65C02 only] 749 | .byte OP_ORA, AM_ABSOLUTE ; $0D 750 | .byte OP_ASL, AM_ABSOLUTE ; $0E 751 | .byte OP_BBR, AM_ABSOLUTE ; $0F [65C02 only] 752 | 753 | .byte OP_BPL, AM_RELATIVE ; $10 754 | .byte OP_ORA, AM_INDIRECT_INDEXED ; $11 755 | .byte OP_ORA, AM_INDIRECT_ZEROPAGE ; $12 [65C02 only] 756 | .byte OP_INV, AM_INVALID ; $13 757 | .byte OP_TRB, AM_ZEROPAGE ; $14 [65C02 only] 758 | .byte OP_ORA, AM_ZEROPAGE_X ; $15 759 | .byte OP_ASL, AM_ZEROPAGE_X ; $16 760 | .byte OP_RMB, AM_ZEROPAGE ; $17 [65C02 only] 761 | .byte OP_CLC, AM_IMPLICIT ; $18 762 | .byte OP_ORA, AM_ABSOLUTE_Y ; $19 763 | .byte OP_INC, AM_ACCUMULATOR ; $1A [65C02 only] 764 | .byte OP_INV, AM_INVALID ; $1B 765 | .byte OP_TRB, AM_ABSOLUTE ; $1C [65C02 only] 766 | .byte OP_ORA, AM_ABSOLUTE_X ; $1D 767 | .byte OP_ASL, AM_ABSOLUTE_X ; $1E 768 | .byte OP_BBR, AM_ABSOLUTE ; $1F [65C02 only] 769 | 770 | .byte OP_JSR, AM_ABSOLUTE ; $20 771 | .byte OP_AND, AM_INDEXED_INDIRECT ; $21 772 | .byte OP_INV, AM_INVALID ; $22 773 | .byte OP_INV, AM_INVALID ; $23 774 | .byte OP_BIT, AM_ZEROPAGE ; $24 775 | .byte OP_AND, AM_ZEROPAGE ; $25 776 | .byte OP_ROL, AM_ZEROPAGE ; $26 777 | .byte OP_RMB, AM_ZEROPAGE ; $27 [65C02 only] 778 | .byte OP_PLP, AM_IMPLICIT ; $28 779 | .byte OP_AND, AM_IMMEDIATE ; $29 780 | .byte OP_ROL, AM_ACCUMULATOR ; $2A 781 | .byte OP_INV, AM_INVALID ; $2B 782 | .byte OP_BIT, AM_ABSOLUTE ; $2C 783 | .byte OP_AND, AM_ABSOLUTE ; $2D 784 | .byte OP_ROL, AM_ABSOLUTE ; $2E 785 | .byte OP_BBR, AM_ABSOLUTE ; $2F [65C02 only] 786 | 787 | .byte OP_BMI, AM_RELATIVE ; $30 788 | .byte OP_AND, AM_INDIRECT_INDEXED ; $31 [65C02 only] 789 | .byte OP_AND, AM_INDIRECT_ZEROPAGE ; $32 [65C02 only] 790 | .byte OP_INV, AM_INVALID ; $33 791 | .byte OP_BIT, AM_ZEROPAGE_X ; $34 [65C02 only] 792 | .byte OP_AND, AM_ZEROPAGE_X ; $35 793 | .byte OP_ROL, AM_ZEROPAGE_X ; $36 794 | .byte OP_RMB, AM_ZEROPAGE ; $37 [65C02 only] 795 | .byte OP_SEC, AM_IMPLICIT ; $38 796 | .byte OP_AND, AM_ABSOLUTE_Y ; $39 797 | .byte OP_DEC, AM_ACCUMULATOR ; $3A [65C02 only] 798 | .byte OP_INV, AM_INVALID ; $3B 799 | .byte OP_BIT, AM_ABSOLUTE_X ; $3C [65C02 only] 800 | .byte OP_AND, AM_ABSOLUTE_X ; $3D 801 | .byte OP_ROL, AM_ABSOLUTE_X ; $3E 802 | .byte OP_BBR, AM_ABSOLUTE ; $3F [65C02 only] 803 | 804 | .byte OP_RTI, AM_IMPLICIT ; $40 805 | .byte OP_EOR, AM_INDEXED_INDIRECT ; $41 806 | .byte OP_INV, AM_INVALID ; $42 807 | .byte OP_INV, AM_INVALID ; $43 808 | .byte OP_INV, AM_INVALID ; $44 809 | .byte OP_EOR, AM_ZEROPAGE ; $45 810 | .byte OP_LSR, AM_ZEROPAGE ; $46 811 | .byte OP_RMB, AM_ZEROPAGE ; $47 [65C02 only] 812 | .byte OP_PHA, AM_IMPLICIT ; $48 813 | .byte OP_EOR, AM_IMMEDIATE ; $49 814 | .byte OP_LSR, AM_ACCUMULATOR ; $4A 815 | .byte OP_INV, AM_INVALID ; $4B 816 | .byte OP_JMP, AM_ABSOLUTE ; $4C 817 | .byte OP_EOR, AM_ABSOLUTE ; $4D 818 | .byte OP_LSR, AM_ABSOLUTE ; $4E 819 | .byte OP_BBR, AM_ABSOLUTE ; $4F [65C02 only] 820 | 821 | .byte OP_BVC, AM_RELATIVE ; $50 822 | .byte OP_EOR, AM_INDIRECT_INDEXED ; $51 823 | .byte OP_EOR, AM_INDIRECT_ZEROPAGE ; $52 [65C02 only] 824 | .byte OP_INV, AM_INVALID ; $53 825 | .byte OP_INV, AM_INVALID ; $54 826 | .byte OP_EOR, AM_ZEROPAGE_X ; $55 827 | .byte OP_LSR, AM_ZEROPAGE_X ; $56 828 | .byte OP_RMB, AM_ZEROPAGE ; $57 [65C02 only] 829 | .byte OP_CLI, AM_IMPLICIT ; $58 830 | .byte OP_EOR, AM_ABSOLUTE_Y ; $59 831 | .byte OP_PHY, AM_IMPLICIT ; $5A [65C02 only] 832 | .byte OP_INV, AM_INVALID ; $5B 833 | .byte OP_INV, AM_INVALID ; $5C 834 | .byte OP_EOR, AM_ABSOLUTE_X ; $5D 835 | .byte OP_LSR, AM_ABSOLUTE_X ; $5E 836 | .byte OP_BBR, AM_ABSOLUTE ; $5F [65C02 only] 837 | 838 | .byte OP_RTS, AM_IMPLICIT ; $60 839 | .byte OP_ADC, AM_INDEXED_INDIRECT ; $61 840 | .byte OP_INV, AM_INVALID ; $62 841 | .byte OP_INV, AM_INVALID ; $63 842 | .byte OP_STZ, AM_ZEROPAGE ; $64 [65C02 only] 843 | .byte OP_ADC, AM_ZEROPAGE ; $65 844 | .byte OP_ROR, AM_ZEROPAGE ; $66 845 | .byte OP_RMB, AM_ZEROPAGE ; $67 [65C02 only] 846 | .byte OP_PLA, AM_IMPLICIT ; $68 847 | .byte OP_ADC, AM_IMMEDIATE ; $69 848 | .byte OP_ROR, AM_ACCUMULATOR ; $6A 849 | .byte OP_INV, AM_INVALID ; $6B 850 | .byte OP_JMP, AM_INDIRECT ; $6C 851 | .byte OP_ADC, AM_ABSOLUTE ; $6D 852 | .byte OP_ROR, AM_ABSOLUTE ; $6E 853 | .byte OP_BBR, AM_ABSOLUTE ; $6F [65C02 only] 854 | 855 | .byte OP_BVS, AM_RELATIVE ; $70 856 | .byte OP_ADC, AM_INDIRECT_INDEXED ; $71 857 | .byte OP_ADC, AM_INDIRECT_ZEROPAGE ; $72 [65C02 only] 858 | .byte OP_INV, AM_INVALID ; $73 859 | .byte OP_STZ, AM_ZEROPAGE_X ; $74 [65C02 only] 860 | .byte OP_ADC, AM_ZEROPAGE_X ; $75 861 | .byte OP_ROR, AM_ZEROPAGE_X ; $76 862 | .byte OP_RMB, AM_ZEROPAGE ; $77 [65C02 only] 863 | .byte OP_SEI, AM_IMPLICIT ; $78 864 | .byte OP_ADC, AM_ABSOLUTE_Y ; $79 865 | .byte OP_PLY, AM_IMPLICIT ; $7A [65C02 only] 866 | .byte OP_INV, AM_INVALID ; $7B 867 | .byte OP_JMP, AM_ABSOLUTE_INDEXED_INDIRECT ; $7C [65C02 only] 868 | .byte OP_ADC, AM_ABSOLUTE_X ; $7D 869 | .byte OP_ROR, AM_ABSOLUTE_X ; $7E 870 | .byte OP_BBR, AM_ABSOLUTE ; $7F [65C02 only] 871 | ; .export OPCODES2 872 | OPCODES2: 873 | .byte OP_BRA, AM_RELATIVE ; $80 [65C02 only] 874 | .byte OP_STA, AM_INDEXED_INDIRECT ; $81 875 | .byte OP_INV, AM_INVALID ; $82 876 | .byte OP_INV, AM_INVALID ; $83 877 | .byte OP_STY, AM_ZEROPAGE ; $84 878 | .byte OP_STA, AM_ZEROPAGE ; $85 879 | .byte OP_STX, AM_ZEROPAGE ; $86 880 | .byte OP_SMB, AM_ZEROPAGE ; $87 [65C02 only] 881 | .byte OP_DEY, AM_IMPLICIT ; $88 882 | .byte OP_BIT, AM_IMMEDIATE ; $89 [65C02 only] 883 | .byte OP_TXA, AM_IMPLICIT ; $8A 884 | .byte OP_INV, AM_INVALID ; $8B 885 | .byte OP_STY, AM_ABSOLUTE ; $8C 886 | .byte OP_STA, AM_ABSOLUTE ; $8D 887 | .byte OP_STX, AM_ABSOLUTE ; $8E 888 | .byte OP_BBS, AM_ABSOLUTE ; $8F [65C02 only] 889 | 890 | .byte OP_BCC, AM_RELATIVE ; $90 891 | .byte OP_STA, AM_INDIRECT_INDEXED ; $91 892 | .byte OP_STA, AM_INDIRECT_ZEROPAGE ; $92 [65C02 only] 893 | .byte OP_INV, AM_INVALID ; $93 894 | .byte OP_STY, AM_ZEROPAGE_X ; $94 895 | .byte OP_STA, AM_ZEROPAGE_X ; $95 896 | .byte OP_STX, AM_ZEROPAGE_Y ; $96 897 | .byte OP_SMB, AM_ZEROPAGE ; $97 [65C02 only] 898 | .byte OP_TYA, AM_IMPLICIT ; $98 899 | .byte OP_STA, AM_ABSOLUTE_Y ; $99 900 | .byte OP_TXS, AM_IMPLICIT ; $9A 901 | .byte OP_INV, AM_INVALID ; $9B 902 | .byte OP_STZ, AM_ABSOLUTE ; $9C [65C02 only] 903 | .byte OP_STA, AM_ABSOLUTE_X ; $9D 904 | .byte OP_STZ, AM_ABSOLUTE_X ; $9E [65C02 only] 905 | .byte OP_BBS, AM_ABSOLUTE ; $9F [65C02 only] 906 | 907 | .byte OP_LDY, AM_IMMEDIATE ; $A0 908 | .byte OP_LDA, AM_INDEXED_INDIRECT ; $A1 909 | .byte OP_LDX, AM_IMMEDIATE ; $A2 910 | .byte OP_INV, AM_INVALID ; $A3 911 | .byte OP_LDY, AM_ZEROPAGE ; $A4 912 | .byte OP_LDA, AM_ZEROPAGE ; $A5 913 | .byte OP_LDX, AM_ZEROPAGE ; $A6 914 | .byte OP_SMB, AM_ZEROPAGE ; $A7 [65C02 only] 915 | .byte OP_TAY, AM_IMPLICIT ; $A8 916 | .byte OP_LDA, AM_IMMEDIATE ; $A9 917 | .byte OP_TAX, AM_IMPLICIT ; $AA 918 | .byte OP_INV, AM_INVALID ; $AB 919 | .byte OP_LDY, AM_ABSOLUTE ; $AC 920 | .byte OP_LDA, AM_ABSOLUTE ; $AD 921 | .byte OP_LDX, AM_ABSOLUTE ; $AE 922 | .byte OP_BBS, AM_ABSOLUTE ; $AF [65C02 only] 923 | 924 | .byte OP_BCS, AM_RELATIVE ; $B0 925 | .byte OP_LDA, AM_INDIRECT_INDEXED ; $B1 926 | .byte OP_LDA, AM_INDIRECT_ZEROPAGE ; $B2 [65C02 only] 927 | .byte OP_INV, AM_INVALID ; $B3 928 | .byte OP_LDY, AM_ZEROPAGE_X ; $B4 929 | .byte OP_LDA, AM_ZEROPAGE_X ; $B5 930 | .byte OP_LDX, AM_ZEROPAGE_Y ; $B6 931 | .byte OP_SMB, AM_ZEROPAGE ; $B7 [65C02 only] 932 | .byte OP_CLV, AM_IMPLICIT ; $B8 933 | .byte OP_LDA, AM_ABSOLUTE_Y ; $B9 934 | .byte OP_TSX, AM_IMPLICIT ; $BA 935 | .byte OP_INV, AM_INVALID ; $BB 936 | .byte OP_LDY, AM_ABSOLUTE_X ; $BC 937 | .byte OP_LDA, AM_ABSOLUTE_X ; $BD 938 | .byte OP_LDX, AM_ABSOLUTE_Y ; $BE 939 | .byte OP_BBS, AM_ABSOLUTE ; $BF [65C02 only] 940 | 941 | .byte OP_CPY, AM_IMMEDIATE ; $C0 942 | .byte OP_CMP, AM_INDEXED_INDIRECT ; $C1 943 | .byte OP_INV, AM_INVALID ; $C2 944 | .byte OP_INV, AM_INVALID ; $C3 945 | .byte OP_CPY, AM_ZEROPAGE ; $C4 946 | .byte OP_CMP, AM_ZEROPAGE ; $C5 947 | .byte OP_DEC, AM_ZEROPAGE ; $C6 948 | .byte OP_SMB, AM_ZEROPAGE ; $C7 [65C02 only] 949 | .byte OP_INY, AM_IMPLICIT ; $C8 950 | .byte OP_CMP, AM_IMMEDIATE ; $C9 951 | .byte OP_DEX, AM_IMPLICIT ; $CA 952 | .byte OP_WAI, AM_IMPLICIT ; $CB [WDC 65C02 only] 953 | .byte OP_CPY, AM_ABSOLUTE ; $CC 954 | .byte OP_CMP, AM_ABSOLUTE ; $CD 955 | .byte OP_DEC, AM_ABSOLUTE ; $CE 956 | .byte OP_BBS, AM_ABSOLUTE ; $CF [65C02 only] 957 | 958 | .byte OP_BNE, AM_RELATIVE ; $D0 959 | .byte OP_CMP, AM_INDIRECT_INDEXED ; $D1 960 | .byte OP_CMP, AM_INDIRECT_ZEROPAGE ; $D2 [65C02 only] 961 | .byte OP_INV, AM_INVALID ; $D3 962 | .byte OP_INV, AM_INVALID ; $D4 963 | .byte OP_CMP, AM_ZEROPAGE_X ; $D5 964 | .byte OP_DEC, AM_ZEROPAGE_X ; $D6 965 | .byte OP_SMB, AM_ZEROPAGE ; $D7 [65C02 only] 966 | .byte OP_CLD, AM_IMPLICIT ; $D8 967 | .byte OP_CMP, AM_ABSOLUTE_Y ; $D9 968 | .byte OP_PHX, AM_IMPLICIT ; $DA [65C02 only] 969 | .byte OP_STP, AM_IMPLICIT ; $DB [WDC 65C02 only] 970 | .byte OP_INV, AM_INVALID ; $DC 971 | .byte OP_CMP, AM_ABSOLUTE_X ; $DD 972 | .byte OP_DEC, AM_ABSOLUTE_X ; $DE 973 | .byte OP_BBS, AM_ABSOLUTE ; $DF [65C02 only] 974 | 975 | .byte OP_CPX, AM_IMMEDIATE ; $E0 976 | .byte OP_SBC, AM_INDEXED_INDIRECT ; $E1 977 | .byte OP_INV, AM_INVALID ; $E2 978 | .byte OP_INV, AM_INVALID ; $E3 979 | .byte OP_CPX, AM_ZEROPAGE ; $E4 980 | .byte OP_SBC, AM_ZEROPAGE ; $E5 981 | .byte OP_INC, AM_ZEROPAGE ; $E6 982 | .byte OP_SMB, AM_ZEROPAGE ; $E7 [65C02 only] 983 | .byte OP_INX, AM_IMPLICIT ; $E8 984 | .byte OP_SBC, AM_IMMEDIATE ; $E9 985 | .byte OP_NOP, AM_IMPLICIT ; $EA 986 | .byte OP_INV, AM_INVALID ; $EB 987 | .byte OP_CPX, AM_ABSOLUTE ; $EC 988 | .byte OP_SBC, AM_ABSOLUTE ; $ED 989 | .byte OP_INC, AM_ABSOLUTE ; $EE 990 | .byte OP_BBS, AM_ABSOLUTE ; $EF [65C02 only] 991 | 992 | .byte OP_BEQ, AM_RELATIVE ; $F0 993 | .byte OP_SBC, AM_INDIRECT_INDEXED ; $F1 994 | .byte OP_SBC, AM_INDIRECT_ZEROPAGE ; $F2 [65C02 only] 995 | .byte OP_INV, AM_INVALID ; $F3 996 | .byte OP_INV, AM_INVALID ; $F4 997 | .byte OP_SBC, AM_ZEROPAGE_X ; $F5 998 | .byte OP_INC, AM_ZEROPAGE_X ; $F6 999 | .byte OP_SMB, AM_ZEROPAGE ; $F7 [65C02 only] 1000 | .byte OP_SED, AM_IMPLICIT ; $F8 1001 | .byte OP_SBC, AM_ABSOLUTE_Y ; $F9 1002 | .byte OP_PLX, AM_IMPLICIT ; $FA [65C02 only] 1003 | .byte OP_INV, AM_INVALID ; $FB 1004 | .byte OP_INV, AM_INVALID ; $FC 1005 | .byte OP_SBC, AM_ABSOLUTE_X ; $FD 1006 | .byte OP_INC, AM_ABSOLUTE_X ; $FE 1007 | .byte OP_BBS, AM_ABSOLUTE ; $FF [65C02 only] 1008 | 1009 | ; *** Strings *** 1010 | 1011 | ContinueString: 1012 | .byte " TO CONTINUE, TO STOP",0 1013 | -------------------------------------------------------------------------------- /M-OS-6502/SW_vtl2a.asm: -------------------------------------------------------------------------------- 1 | ;234567890123456789012345678901234567890123456789012345 2 | ;------------------------------------------------------ 3 | ; VTL-2 for the 6502 (VTL02) 4 | ; Original Altair 680b version by 5 | ; Frank McCoy and Gary Shannon 1977 6 | ; Adapted to the 6502 by Michael T. Barry 2012 7 | ; Thanks to sbprojects.com for a very nice assembler! 8 | ; Modified for the Kowalski simulator by Klaus2m5 9 | ; 10 | ;Copyright (c) 2012, Michael T. Barry 11 | ;All rights reserved. 12 | ; 13 | ;Redistribution and use in source and binary forms, 14 | ; with or without modification, are permitted provided 15 | ; that the following conditions are met: 16 | ; 17 | ;1. Redistributions of source code must retain the 18 | ; above copyright notice, this list of conditions and 19 | ; the following disclaimer. 20 | ;2. Redistributions in binary form must reproduce the 21 | ; above copyright notice, this list of conditions and 22 | ; the following disclaimer in the documentation and/ 23 | ; or other materials provided with the distribution. 24 | ; 25 | ;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 26 | ; CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 27 | ; WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | ; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 | ; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 30 | ; SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 31 | ; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 32 | ; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 33 | ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 34 | ; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 | ; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 36 | ; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 37 | ; TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 38 | ; ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 39 | ; ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | ; 41 | ; Notes concerning this version: 42 | ; {&} and {*} are initialized on entry. 43 | ; Division by zero returns a quotient of 65535 (the 44 | ; original 6800 version froze). 45 | ; The 6502 has NO 16-bit registers (other than PC) 46 | ; and less overall register space than the 6800, so 47 | ; it was necessary to reserve some obscure VTL02 48 | ; variables {@ _ $ ( ) 0 1 2 3 4 5 6 7 8 9 :} for 49 | ; the interpreter's internal use (the 6800 version 50 | ; also uses several of these, but with different 51 | ; designations). The deep nesting of parentheses 52 | ; also puts {; < =} in danger of corruption. For 53 | ; example, A=((((((((1)))))))) sets both {A} and 54 | ; {;} to the value 1. 55 | ; Users wishing to call a machine language subroutine 56 | ; via the system variable {>} must first set the 57 | ; system variable {"} to the proper address vector 58 | ; (for example, "=768). 59 | ; The x register is used to point to a simple VTL02 60 | ; variable (it can't point explicitly to an array 61 | ; element like the 6800 version because it's only 62 | ; 8-bits). In the comments, var[x] refers to the 63 | ; 16-bit contents of the zero-page variable pointed 64 | ; to by register x (residing at addresses x, x+1). 65 | ; The y register is used as a pointer offset inside a 66 | ; VTL02 statement (it can easily handle the maximum 67 | ; statement length of about 128 bytes). In the 68 | ; comments, @[y] refers to the 16-bit address 69 | ; formed by adding register y to the value in {@}. 70 | ; The structure and flow of this interpreter is 71 | ; similar to the 6800 version, but it has been re- 72 | ; organized in a more 6502-friendly format (the 73 | ; 6502 has no 'bsr' instruction, so the 'stuffing' 74 | ; of subroutines within 128 bytes of the caller is 75 | ; only advantageous for conditional branches). 76 | ; I designed this version to duplicate the OFFICIALLY 77 | ; DOCUMENTED behavior of Frank's 6800 version: 78 | ; http://www.altair680kit.com/manuals/Altair_ 79 | ; 680-VTL-2%20Manual-05-Beta_1-Searchable.pdf 80 | ; Both versions ignore all syntax errors and plow 81 | ; through VTL-2 programs with the assumption that 82 | ; they are "correct", but in their own unique ways, 83 | ; so any claims of compatibility are null and void 84 | ; for VTL-2 code brave (or stupid) enough to stray 85 | ; from the beaten path. 86 | ; This version is wound rather tightly, in a failed 87 | ; attempt to fit it into 768 bytes like the 6800 88 | ; version; many structured programming principles 89 | ; were sacrificed in that effort. The 6502 simply 90 | ; requires more instructions than the 6800 does to 91 | ; manipulate 16-bit quantities, but the overall 92 | ; execution speed should be comparable due to the 93 | ; 6502's slightly lower average clocks/instruction 94 | ; ratio. As it is now, it fits into 1k with room 95 | ; to spare. When coding VTL02, I chose compactness 96 | ; over execution speed at every opportunity; a 97 | ; higher-performance and/or more feature-laden 98 | ; version (with error detection perhaps?) should 99 | ; still fit into 1k. Are there any volunteers? 100 | ; VTL02 is my free gift (?) to the world. It may be 101 | ; freely copied, shared, and/or modified by anyone 102 | ; interested in doing so, with only the stipulation 103 | ; that any liabilities arising from its use are 104 | ; limited to the price of VTL02 (nothing). 105 | ;------------------------------------------------------ 106 | ; VTL02 variables occupy RAM addresses $0080 to $00ff. 107 | ; They are little-endian, in the 6502 tradition. 108 | ; The use of lower-case and some control characters for 109 | ; variable names is allowed, but not recommended; any 110 | ; attempts to do so would likely result in chaos. 111 | ; Variables tagged with an asterisk are used internally 112 | ; by the interpreter and may change without warning. 113 | ; {@ _} cannot be entered via the command line, and 114 | ; {$ ( ) 0..9 : > ?} are (usually) intercepted by the 115 | ; interpreter, so their internal use by VTL02 is 116 | ; "safe". The same cannot be said for {; < =}, so 117 | ; be careful! 118 | .alias at $80 ;{@}* interpreter text pointer 119 | ; VTL02 standard user variable space 120 | ; $82 {A B C .. X Y Z [ \ ] ^} 121 | ; VTL02 system variable space 122 | .alias under $be ;{_}* interpreter temp storage 123 | ; $c0 { } space is a valid variable 124 | .alias bang $c2 ;{!} return line number 125 | .alias quote $c4 ;{"} user ml subroutine vector 126 | .alias pound $c6 ;{#} current line number 127 | .alias dolr $c8 ;{$}* temp storage / char i/o 128 | .alias remn $ca ;{%} remainder of last division 129 | .alias ampr $cc ;{&} pointer to start of array 130 | .alias tick $ce ;{'} pseudo-random number 131 | .alias lparen $d0 ;{(}* old line # / begin sub-exp 132 | .alias rparen $d2 ;{)}* temp storage / end sub-exp 133 | .alias star $d4 ;{*} pointer to end of free mem 134 | ; $d6 {+ , - . /} valid variables 135 | ; Interpreter argument stack space 136 | .alias arg $e0 ;{0 1 2 3 4 5 6 7 8 9 :}* 137 | ; Rarely used variables and argument stack overflow 138 | ; $f6 {; < =}* valid variables 139 | .alias gthan $fc ;{>}* call user ml subroutine 140 | .alias ques $fe ;{?}* temp / terminal i/o 141 | ; 142 | .alias nulstk $01ff ;system stack resides in page 1 143 | .alias linbuf $0200 ;input line buffer 144 | .alias prgm $400 ;VTL program grows from here ... 145 | .alias himem $8000 ;up to the top of user RAM 146 | ;------------------------------------------------------ 147 | ; Equates specific to the Kowalski simulator 148 | ;.alias vtl02 $e800 ;interpreter cold entry point 149 | ; (warm entry point is startok) 150 | ;.alias io_area $f000 ;configure simulator terminal I/O 151 | ;.alias acia_tx io_area+1 ;acia tx data register 152 | ;.alias acia_rx io_area+4 ;acia rx data register 153 | ;====================================================== 154 | ;.org vtl02 155 | ;------------------------------------------------------ 156 | ; Initialize program area pointers and start VTL02 157 | ; 158 | v_startx: 159 | cld 160 | lda # empty program 162 | lda #>prgm 163 | sta ampr+1 164 | lda # top of user RAM 166 | lda #>himem 167 | sta star+1 168 | startok: 169 | sec ;request "OK" message 170 | ; - - - - - - - - - - - - - - - - - - - - - - - - - - - 171 | ; Start/restart VTL02 command line with program intact 172 | ; 173 | start: 174 | ldx # 0 201 | bne xloop ;then start execution @ {#} 202 | eloop2: 203 | sec ;if program mode and {#} = 0 204 | beq xloop ;then execute next line 205 | lda pound+1 ;(false branch condition) 206 | cmp lparen+1 207 | bne branch ;else has {#} changed? 208 | lda pound 209 | cmp lparen 210 | beq xloop ;no: execute next line (cs) 211 | branch: 212 | ldy lparen+1 213 | ldx lparen ;yes: execute a VTL02 branch 214 | inx ;(cs: forward, cc: backward) 215 | bne branch2 ;{!} = {(} + 1 (return ptr) 216 | iny 217 | branch2: 218 | stx bang 219 | sty bang+1 220 | xloop: 221 | jsr findln ;find first/next line >= {#} 222 | iny ;point to left-side of statement 223 | bne eloop ;execute statement at new {#} 224 | ;------------------------------------------------------ 225 | ; Delete/insert program line or list program 226 | ; 227 | stmnt: 228 | clc 229 | lda pound ;{#} = 0? 230 | ora pound+1 ;no: delete/insert line 231 | bne skp2 ;yes: list program to terminal 232 | ; - - - - - - - - - - - - - - - - - - - - - - - - - - - 233 | ; List program to terminal and restart "OK" prompt 234 | ; entry: Carry must be clear 235 | ; uses: findln, outch, prnum, prstr, {@ ( )} 236 | ; 237 | list_: 238 | jsr findln ;find program line >= {#} 239 | ldx #lparen ;line number for prnum 240 | jsr prnum ;print the line number 241 | lda #$20 ;print a space instead of the 242 | jsr outch ;line length byte 243 | lda #0 ;zero for delimiter 244 | jsr prstr ;print the rest of the line 245 | sec ;continue at the next line 246 | bcs list_ ;(always taken) 247 | ;------------------------------------------------------ 248 | ; Delete/insert program line and restart command prompt 249 | ; entry: Carry must be clear 250 | ; uses: find, start, {@ _ # & * (}, linbuf 251 | ; 252 | skp2: 253 | tya ;save linbuf offset pointer 254 | pha 255 | jsr find ;locate first line >= {#} 256 | bcs insrt 257 | lda lparen 258 | cmp pound ;if line doesn't already exist 259 | bne insrt ;then skip deletion process 260 | lda lparen+1 261 | eor pound+1 262 | bne insrt 263 | tax ;x = 0 264 | lda (at),y 265 | tay ;y = length of line to delete 266 | ;eor #-1 267 | eor #$ff 268 | adc ampr ;{&} = {&} - y 269 | sta ampr 270 | bcs delt 271 | dec ampr+1 272 | delt: 273 | lda at 274 | sta under ;{_} = {@} 275 | lda at+1 276 | sta under+1 277 | delt2: 278 | lda under 279 | cmp ampr ;delete the line 280 | lda under+1 281 | sbc ampr+1 282 | bcs insrt 283 | lda (under),y 284 | sta (under,x) 285 | inc under 286 | bne delt2 287 | inc under+1 288 | bcc delt2 ;(always taken) 289 | insrt: 290 | pla 291 | tax ;x = linbuf offset pointer 292 | lda pound 293 | pha ;push the new line number on 294 | lda pound+1 ;the system stack 295 | pha 296 | ldy #2 297 | cntln: 298 | inx 299 | iny ;determine new line length in y 300 | lda linbuf-1,x ;and push statement string on 301 | pha ;the system stack 302 | bne cntln 303 | cpy #4 ;if empty line then skip the 304 | bcc jstart ;insertion process 305 | tax ;x = 0 306 | tya 307 | clc 308 | adc ampr ;calculate new program end 309 | sta under ;{_} = {&} + y 310 | txa 311 | adc ampr+1 312 | sta under+1 313 | lda under 314 | cmp star 315 | lda under+1 ;if {_} >= {*} then the program 316 | sbc star+1 ;won't fit in available RAM, 317 | bcs jstart ;so abort to the "OK" prompt 318 | slide: 319 | lda ampr 320 | bne slide2 321 | dec ampr+1 322 | slide2: 323 | dec ampr 324 | lda ampr 325 | cmp at 326 | lda ampr+1 327 | sbc at+1 328 | bcc move ;slide open a gap inside the 329 | lda (ampr,x) ;program just big enough to 330 | sta (ampr),y ;hold the new line 331 | bcs slide ;(always taken) 332 | move: 333 | tya 334 | tax ;x = new line length 335 | move2: 336 | pla ;pull the statement string and 337 | dey ;the new line number and store 338 | sta (at),y ;them in the program gap 339 | bne move2 340 | ldy #2 341 | txa 342 | sta (at),y ;store length after line number 343 | lda under 344 | sta ampr ;{&} = {_} 345 | lda under+1 346 | sta ampr+1 347 | jstart: 348 | jmp start ;dump stack, restart cmd prompt 349 | ;------------------------------------------------------ 350 | ; Point @[y] to the first/next program line >= {#} 351 | ; entry: (cc): start search at beginning of program 352 | ; (cs): start search at next line 353 | ; ({@} -> beginning of current line) 354 | ; uses: find, jstart, prgm, {@ # & (} 355 | ; exit: if line not found then abort to "OK" prompt 356 | ; else {@} -> found line, {#} = {(} = actual 357 | ; line number, y = 2, (cc) 358 | ; 359 | findln: 360 | jsr find ;find first/next line >= {#} 361 | bcs jstart ;if end then restart "OK" prompt 362 | lda lparen 363 | sta pound ;{#} = {(} 364 | lda lparen+1 365 | sta pound+1 366 | rts 367 | ;------------------------------------------------------ 368 | ; {?="...} handler; called from 'exec' 369 | ; list line handler; called from 'list' 370 | ; 371 | prstr: 372 | iny ;skip over the " or length byte 373 | tax ;x = delimiter, fall through 374 | ; - - - - - - - - - - - - - - - - - - - - - - - - - - - 375 | ; Print a string at @[y] 376 | ; x holds the delimiter char, which is skipped over, 377 | ; not printed (a null byte is always a delimiter) 378 | ; pauses before returning if a key was pressed and 379 | ; waits for another 380 | ; restarts the command prompt with user program intact 381 | ; if either key was ctrl-c 382 | ; escapes out eventually if delimiter or null not found 383 | ; entry: @[y] -> string, x = delimiter char 384 | ; uses: kbd, inch, keyin, start, outch, outrts 385 | ; exit: (normal) @[y] -> null or byte after delimiter 386 | ; (ctrl-c) dump the stack & restart "OK" prompt 387 | ; 388 | prmsg: 389 | txa 390 | cmp (at),y ;found delimiter or null? 391 | beq prmsg2 ;yes: finish up 392 | lda (at),y 393 | beq prmsg2 394 | jsr outch ;no: print char to user 395 | iny ;terminal and loop 396 | bpl prmsg ;(with safety escape) 397 | prmsg2: 398 | tax ;save closing delimiter 399 | ;lda acia_rx ;any key = pause 400 | jsr j_rchr ;any key 401 | bcc prout ;no: continue printing 402 | ;beq prout ;no: continue printing 403 | cmp #$03 ; ctrl-c? 404 | beq jstart ; yes: abort to "OK" prompt 405 | prpause: 406 | ;lda acia_rx ;any key = resume 407 | jsr j_rchr ;any key 408 | bcc prpause ;no: pause loop 409 | ;beq prpause ;no: pause loop 410 | cmp #$03 ; ctrl-c? 411 | beq jstart ; yes: abort to "OK" prompt 412 | prout: 413 | txa ;retrieve closing delimiter 414 | beq outcr ;always cr after null delimiter 415 | iny ;skip over the delimiter 416 | lda (at),y ;if trailing char is ';' then 417 | cmp #$3b ;suppress the carriage return 418 | beq outrts 419 | outcr: 420 | lda #LINE_END ;cr to terminal 421 | bne outch ;(always taken) 422 | ;------------------------------------------------------ 423 | ; Read char from user terminal into a with echo 424 | ; 425 | inch: 426 | jsr j_rchr ; read character 427 | bcs inch ; wait for character 428 | ;; sty dolr ; save y reg 429 | ;;nobyw: 430 | ;; lda acia_rx ; test data available 431 | ;; beq nobyw ; branch if no byte waiting 432 | ;; cmp #10 ; remove lf to allow paste 433 | ;; beq nobyw ; in the Kowalski I/O window 434 | ; some terminals send del when bs is pressed! 435 | ; cmp #127 ; convert delete to backspace 436 | ; bne conv_bs2del 437 | ; lda #8 438 | ;conv_bs2del 439 | ; code below would filter terminal escape sequences 440 | ; but requires a specific 10ms tick timer to work 441 | ; cmp #27 ; escape? 442 | ; bne skip_esc_no 443 | ; ldy #5 ; timer loop - 5*10ms 444 | ;skip_esc_next 445 | ; lda #1 ; ack last tick 446 | ; sta acia_st 447 | ;skip_esc_wait 448 | ; lda acia_st 449 | ; and #1 ; next tick 450 | ; beq skip_esc_wait 451 | ; dey 452 | ; bne skip_esc_next 453 | ;skip_esc_discard 454 | ; iny ; any data = y > 1 455 | ; lda acia_rx 456 | ; bne skip_esc_discard 457 | ; cpy #1 458 | ; bne nobyw 459 | ;skip_esc_esc ; escape only - send to vtl 460 | ; lda #27 461 | ; rts ; don't echo escape to terminal 462 | ;skip_esc_no 463 | ;; ldy dolr ; restore y reg 464 | and #$7f ; ensure char is positive ascii 465 | cmp #$03 ; ctrl-c? 466 | beq jstart ; yes: abort to "OK" prompt 467 | ; - - - - - - - - - - - - - - - - - - - - - - - - - - - 468 | ; Print ascii char in a to stdout 469 | ; 470 | outch: 471 | ; convert cr to cr lf 472 | ;; cmp #13 ; cr 473 | ;; bne skip_cr 474 | ;; lda #10 475 | ;; sta acia_tx 476 | ;; jsr j_wchr 477 | ;; lda #13 478 | skip_cr: 479 | ; convert bs to erasing bs 480 | ; cmp #8 ; backspace? 481 | ; bne skip_bs 482 | ; sta acia_tx ; make erasing backspace 483 | ; lda #' ' 484 | ; sta acia_tx 485 | ; lda #8 486 | ;skip_bs 487 | ;; sta acia_tx ; send byte to acia 488 | jsr j_wchr 489 | outrts: 490 | rts 491 | ;------------------------------------------------------ 492 | ; Execute a hopefully valid VTL02 statement at @[y] 493 | ; entry: @[y] -> left-side of statement 494 | ; uses: nearly everything 495 | ; exit: note to {>} users: no registers or variables 496 | ; are required to be preserved except the 497 | ; system stack pointer, the text base pointer 498 | ; {@}, and the original line number {(} 499 | ; if there is a {"} directly after the assign- 500 | ; ment operator, the statement will execute 501 | ; as {?="...}, regardless of the variable 502 | ; named on the left-side 503 | ; 504 | exec: 505 | lda (at),y ;fetch left-side variable name 506 | beq execrts ;do nothing if null statement 507 | iny 508 | ldx #arg ;initialize argument pointer 509 | jsr convp ;arg[{0}] = address of left-side 510 | bne exec1 ;variable 511 | lda arg 512 | cmp #rparen ;full line comment? 513 | beq execrts ;yes: do nothing with the rest 514 | exec1: 515 | iny ;skip over assignment operator 516 | lda (at),y ;is right-side a literal string? 517 | cmp #$22 ;yes: print the string with 518 | beq prstr_x ;trailing ';' check & return 519 | ldx #arg+2 ;point eval to arg[{1}] 520 | jsr eval ;evaluate right-side in arg[{1}] 521 | lda arg+2 522 | ldx arg+1 ;was left-side an array element? 523 | bne exec3 ;yes: skip to default actions 524 | ldx arg 525 | cpx #dolr ;if {$=...} statement then print 526 | beq outch ;arg[{1}] as ascii character 527 | cpx #gthan 528 | bne exec2 ;if {>=...} statement then call 529 | tax ;user machine language routine 530 | lda arg+3 ;with arg[{1}] in a, x regs 531 | jmp (quote) ;(MSB, LSB) 532 | exec2: 533 | cpx #ques ;if {?=...} statement then print 534 | beq prnum0 ;arg[{1}] as unsigned decimal 535 | exec3: 536 | ldy #0 537 | sta (arg),y 538 | adc tick+1 ;store arg[{1}] in the left- 539 | rol ;side variable 540 | tax 541 | iny 542 | lda arg+3 543 | sta (arg),y 544 | adc tick ;pseudo-randomize {'} 545 | rol 546 | sta tick+1 547 | stx tick 548 | execrts: 549 | rts 550 | prstr_x: 551 | jmp prstr 552 | ;------------------------------------------------------ 553 | ; {?=...} handler; called by 'exec' 554 | ; 555 | prnum0: 556 | ldx #arg+2 ;x -> arg[{1}], fall through 557 | ;------------------------------------------------------ 558 | ; Print an unsigned decimal number (0..65535) in var[x] 559 | ; entry: var[x] = number to print 560 | ; uses: div, outch, var[x+2], preserves original {%} 561 | ; exit: var[x] = 0, var[x+2] = 10 562 | ; 563 | prnum: 564 | lda remn 565 | pha ;save {%} 566 | lda remn+1 567 | pha 568 | lda #10 ;divisor = 10 569 | sta 2,x 570 | lda #0 571 | pha ;null delimiter for print 572 | sta 3,x ;repeat { 573 | prnum2: 574 | jsr div ;divide var[x] by 10 575 | lda remn 576 | ora #'0 ;convert remainder to ascii 577 | pha ;stack digits in ascending 578 | lda 0,x ;order ('0' for zero) 579 | ora 1,x 580 | bne prnum2 ;} until var[x] is 0 581 | pla 582 | prnum3: 583 | jsr outch ;print digits in descending 584 | pla ;order until delimiter is 585 | bne prnum3 ;encountered 586 | pla 587 | sta remn+1 ;restore {%} 588 | pla 589 | sta remn 590 | rts 591 | ;------------------------------------------------------ 592 | ; Evaluate a hopefully valid VTL02 expression at @[y] 593 | ; and place its completed value in arg[x] 594 | ; A VTL02 expression is defined as a string of one or 595 | ; more terms, separated by operators and terminated 596 | ; with a null or an unmatched right parenthesis 597 | ; A term is defined as a variable name, a decimal 598 | ; constant, or a parenthesized sub-expression; terms 599 | ; are evaluated strictly from left to right 600 | ; A variable name is defined as a simple variable or an 601 | ; array element expression enclosed in {: )} 602 | ; entry: @[y] -> expression text, x -> argument 603 | ; uses: getval, oper, argument stack area 604 | ; exit: arg[x] = result, @[y] -> next text 605 | ; 606 | eval: 607 | lda #0 608 | sta 0,x ;start evaluation by simulating 609 | sta 1,x ;{0+expression} 610 | lda #$2b 611 | notdn: 612 | pha ;stack alleged operator 613 | inx ;advance the argument stack 614 | inx ;pointer 615 | jsr getval ;arg[x+2] = value of next term 616 | dex 617 | dex 618 | pla ;retrieve and apply the operator 619 | jsr oper ;to arg[x], arg[x+2] 620 | lda (at),y ;end of expression? 621 | beq evalrts ;(null or right parenthesis) 622 | iny 623 | cmp #$29 ;no: skip over the operator 624 | bne notdn ;and continue the evaluation 625 | evalrts: 626 | rts ;yes: return with final result 627 | ;------------------------------------------------------ 628 | ; Put the numeric value of the term at @[y] into var[x] 629 | ; Some examples of valid terms: 123, $, H, (15-:J)/?) 630 | ; 631 | getval: 632 | jsr cvbin ;decimal number at @[y]? 633 | bne getrts ;yes: return with it in var[x] 634 | lda (at),y 635 | iny 636 | cmp #$3f ;user line input? 637 | bne getval2 638 | tya ;yes: 639 | pha 640 | lda at ;save @[y] 641 | pha ;(current expression ptr) 642 | lda at+1 643 | pha 644 | jsr inln ;input expression from user 645 | jsr eval ;evaluate, var[x] = result 646 | pla 647 | sta at+1 648 | pla 649 | sta at ;restore @[y] 650 | pla 651 | tay 652 | rts ;skip over "?" and return 653 | getval2: 654 | cmp #'$ ;user char input? 655 | bne getval3 656 | jsr inch ;yes: input one char 657 | sta 0,x ;var[x] = char 658 | rts ;skip over "$" and return 659 | getval3: 660 | cmp #$28 ;sub-expression? 661 | beq eval ;yes: evaluate it recursively 662 | jsr convp ;no: first set var[x] to the 663 | lda (0,x) ;named variable's address, 664 | pha ;then replace that address 665 | inc 0,x ;with the variable's actual 666 | bne getval4 ;value before returning 667 | inc 1,x 668 | getval4: 669 | lda (0,x) 670 | sta 1,x 671 | pla 672 | sta 0,x 673 | getrts: 674 | rts 675 | ;------------------------------------------------------ 676 | ; Apply the binary operator in a to var[x] and var[x+2] 677 | ; Valid VTL02 operators are +, -, *, /, <, and = 678 | ; Any other operator in a defaults to >= 679 | ; 680 | oper: 681 | cmp #$2b ;addition operator? 682 | bne oper2 ;no: next case 683 | ; - - - - - - - - - - - - - - - - - - - - - - - - - - - 684 | add: 685 | clc 686 | lda 0,x ;var[x] += var[x+2] 687 | adc 2,x 688 | sta 0,x 689 | lda 1,x 690 | adc 3,x 691 | sta 1,x 692 | rts 693 | oper2: 694 | cmp #$2d ;subtraction operator? 695 | bne oper3 ;no: next case 696 | ; - - - - - - - - - - - - - - - - - - - - - - - - - - - 697 | sub: 698 | sec 699 | lda 0,x ;var[x] -= var[x+2] 700 | sbc 2,x 701 | sta 0,x 702 | lda 1,x 703 | sbc 3,x 704 | sta 1,x 705 | rts 706 | oper3: 707 | cmp #$2a ;multiplication operator? 708 | bne oper4 ;no: next case 709 | ; - - - - - - - - - - - - - - - - - - - - - - - - - - - 710 | ; 16-bit unsigned multiply routine 711 | ; overflow is ignored/discarded 712 | ; var[x] *= var[x+2], var[x+2] = 0, {_} is modified 713 | ; 714 | mul: 715 | lda 0,x 716 | sta under 717 | lda 1,x ;{_} = var[x] 718 | sta under+1 719 | lda #0 720 | sta 0,x ;var[x] = 0 721 | sta 1,x 722 | mul2: 723 | lsr under+1 724 | ror under ;{_} /= 2 725 | bcc mul3 726 | jsr add ;form the product in var[x] 727 | mul3: 728 | asl 2,x 729 | rol 3,x ;left-shift var[x+2] 730 | lda 2,x 731 | ora 3,x ;loop until var[x+2] = 0 732 | bne mul2 733 | rts 734 | oper4: 735 | cmp #$2f ;division operator? 736 | bne oper5 ;no: next case 737 | ; - - - - - - - - - - - - - - - - - - - - - - - - - - - 738 | ; 16-bit unsigned division routine 739 | ; var[x] /= var[x+2], {%} = remainder, {_} modified 740 | ; var[x] /= 0 produces {%} = var[x], var[x] = 65535 741 | ; 742 | div: 743 | lda #0 744 | sta remn ;{%} = 0 745 | sta remn+1 746 | lda #16 747 | sta under ;{_} = loop counter 748 | div1: 749 | asl 0,x ;var[x] is gradually replaced 750 | rol 1,x ;with the quotient 751 | rol remn ;{%} is gradually replaced 752 | rol remn+1 ;with the remainder 753 | lda remn 754 | cmp 2,x 755 | lda remn+1 ;partial remainder >= var[x+2]? 756 | sbc 3,x 757 | bcc div2 758 | sta remn+1 ;yes: update the partial 759 | lda remn ;remainder and set the 760 | sbc 2,x ;low bit in the partial 761 | sta remn ;quotient 762 | inc 0,x 763 | div2: 764 | dec under 765 | bne div1 ;loop 16 times 766 | rts 767 | ;------------------------------------------------------ 768 | ; Apply comparison operator in a to var[x] and var[x+2] 769 | ; and place result in var[x] (1: true, 0: false) 770 | ; Warning: Tightly packed spaghetti below! 771 | ; 772 | oper5: 773 | sec ;{_} = -2: less than, 774 | sbc #$3e ;-1: equal, 775 | sta under ;other: greater than or equal 776 | jsr sub ;var[x] -= var[x+2] 777 | inc under ;equality test? 778 | bne oper5b 779 | ora 0,x ;yes: 'or' high and low bytes 780 | beq oper5c ;(cs) if 0 781 | oper5a: 782 | clc ;(cc) if not 0 783 | oper5b: 784 | lda #0 785 | inc under ;less than test? 786 | bne oper5c ;no: default to >= 787 | bcs oper5a ;yes: complement carry 788 | sec 789 | oper5c: 790 | rol 791 | oper5d: 792 | sta 0,x ;var[x] -> simple variable 793 | lda #0 794 | sta 1,x 795 | rts ;var[x] = 1 (true), 0 (false) 796 | ;------------------------------------------------------ 797 | ; Set var[x] to the address of the variable named in a 798 | ; entry: a holds variable name, @[y] -> text holding 799 | ; array element expression (if a = ':') 800 | ; uses: add, eval, oper5d, {&} 801 | ; exit: (eq): var[x] -> var, @[y] unchanged 802 | ; (ne): var[x] -> array element, @[y] -> 803 | ; following text 804 | ; 805 | convp: 806 | cmp #$3a ;array element? 807 | beq varray 808 | asl ;no: var[x] -> simple variable 809 | ora #$80 810 | bmi oper5d 811 | varray: 812 | jsr eval ;yes: evaluate array index at 813 | asl 0,x ;@[y] and advance y 814 | rol 1,x 815 | lda ampr ;var[x] -> array element 816 | sta 2,x 817 | lda ampr+1 818 | sta 3,x 819 | jmp add 820 | ;------------------------------------------------------ 821 | ; If text at @[y] is a decimal constant, translate into 822 | ; var[x] (discarding any overflow) and update y 823 | ; entry: @[y] -> text containing possible constant 824 | ; uses: mul, add, var[x], var[x+2], {@ _ ?} 825 | ; exit: (ne): var[x] = constant, @[y] -> next text 826 | ; (eq): var[x] = 0, @[y] unchanged 827 | ; (cs): in all but the truly strangest cases 828 | ; 829 | cvbin: 830 | sty ques ;save entry text position 831 | lda #0 832 | sta 0,x ;var[x] = 0 833 | sta 1,x 834 | sta 3,x 835 | cvbin2: 836 | lda (at),y ;if char at @[y] is not a 837 | cmp #$3a ;decimal digit then stop 838 | bcs cvbin3 ;the conversion 839 | sbc #$2f 840 | bcc cvbin3 841 | pha ;save decimal digit 842 | lda #10 843 | sta 2,x 844 | jsr mul ;var[x] *= 10 845 | pla ;retrieve decimal digit 846 | sta 2,x 847 | jsr add ;var[x] += digit 848 | iny ;loop for more digits 849 | bpl cvbin2 ;(with safety escape) 850 | cvbin3: 851 | cpy ques ;(ne) if y changed, (eq) if not 852 | rts 853 | ;------------------------------------------------------ 854 | ; Accept input line from user and store it in linbuf, 855 | ; zero-terminated (allows very primitive edit/cancel) 856 | ; entry: (jsr to inln or newln, not inln6) 857 | ; uses: linbuf, inch, outcr, {@} 858 | ; exit: @[y] -> linbuf 859 | ; 860 | inln6: 861 | ; cmp #'@' ;original escape? 862 | cmp #27 ;escape? 863 | beq newln ;yes: discard entire line 864 | iny ;line limit exceeded? 865 | bpl inln2 ;no: keep going 866 | newln: 867 | jsr outcr ;yes: discard entire line 868 | inln: 869 | ldy # input line buffer 871 | ldy #>linbuf 872 | sty at+1 873 | ldy #1 874 | inln5: 875 | dey 876 | bmi newln 877 | inln2: 878 | jsr inch ;get (and echo) one key press 879 | ; cmp #'_' ;original backspace 880 | cmp #8 ;backspace? 881 | beq inln5 ;yes: delete previous char 882 | cmp #$0d ;cr? 883 | bne inln3 884 | jsr outcr 885 | lda #0 ;yes: replace with null 886 | inln3: 887 | sta (at),y ;put key in linbuf 888 | bne inln6 ;continue if not null 889 | tay ;y = 0 890 | rts 891 | ;------------------------------------------------------ 892 | ; Find the first/next stored program line >= {#} 893 | ; entry: (cc): start search at program beginning 894 | ; (cs): start search at next line after {@} 895 | ; uses: prgm, {@ # & (} 896 | ; exit: (cs): {@} >= {&}, {(} = garbage, y = 2 897 | ; (cc): {@} -> found line, {(} = actual line 898 | ; number, y = 2 899 | ; 900 | find: 901 | bcs findnxt ;cs: search begins at next line 902 | lda #>prgm ;cc: search begins at first line 903 | sta at+1 904 | lda # first program line 905 | bcc find1st ;(always taken) 906 | findnxt: 907 | jsr checkat ;if {@} >= {&} then the search 908 | bcs findrts ;failed; return with (cs) 909 | lda at 910 | adc (at),y ;{@} += length of current line 911 | find1st: 912 | sta at 913 | bcc getlpar 914 | inc at+1 915 | getlpar: 916 | ldy #0 917 | lda (at),y 918 | sta lparen ;{(} = current line number 919 | cmp pound ;(invalid if {@} >= {&}, but 920 | iny ;we'll catch that later...) 921 | lda (at),y 922 | sta lparen+1 ;if {(} < {#} then try the next 923 | sbc pound+1 ;program line 924 | bcc findnxt ;else the search is complete 925 | checkat: 926 | ldy #2 927 | lda at ;{@} >= {&} (end of program)? 928 | cmp ampr 929 | lda at+1 ;yes: search failed (cs) 930 | sbc ampr+1 ;no: clear carry 931 | findrts: 932 | rts 933 | ;------------------------------------------------------ 934 | ; .end vtl02 935 | 936 | -------------------------------------------------------------------------------- /M-OS-6502/labelmap.txt: -------------------------------------------------------------------------------- 1 | $0000 | am_invalid | SW_disassembler.asm:130 2 | $0000 | k_string_l | MIOS_defines.asm:48 3 | $0000 | op_inv | SW_disassembler.asm:57 4 | $0001 | am_implicit | SW_disassembler.asm:131 5 | $0001 | k_string_h | MIOS_defines.asm:49 6 | $0001 | op_adc | SW_disassembler.asm:58 7 | $0002 | am_accumulator | SW_disassembler.asm:132 8 | $0002 | k_var1_l | MIOS_defines.asm:50 9 | $0002 | op_and | SW_disassembler.asm:59 10 | $0003 | am_immediate | SW_disassembler.asm:133 11 | $0003 | asciicc | MOS_monitor.asm:6 12 | $0003 | k_var1_h | MIOS_defines.asm:51 13 | $0003 | op_asl | SW_disassembler.asm:60 14 | $0004 | am_zeropage | SW_disassembler.asm:134 15 | $0004 | k_var2_l | MIOS_defines.asm:52 16 | $0004 | op_bcc | SW_disassembler.asm:61 17 | $0005 | am_zeropage_x | SW_disassembler.asm:135 18 | $0005 | k_var2_h | MIOS_defines.asm:53 19 | $0005 | op_bcs | SW_disassembler.asm:62 20 | $0006 | am_zeropage_y | SW_disassembler.asm:136 21 | $0006 | k_var3_l | MIOS_defines.asm:54 22 | $0006 | op_beq | SW_disassembler.asm:63 23 | $0007 | am_relative | SW_disassembler.asm:137 24 | $0007 | k_var3_h | MIOS_defines.asm:55 25 | $0007 | op_bit | SW_disassembler.asm:64 26 | $0008 | am_absolute | SW_disassembler.asm:138 27 | $0008 | asciibs | MOS_monitor.asm:7 28 | $0008 | k_var4_l | MIOS_defines.asm:56 29 | $0008 | op_bmi | SW_disassembler.asm:65 30 | $0009 | am_absolute_x | SW_disassembler.asm:139 31 | $0009 | k_var4_h | MIOS_defines.asm:57 32 | $0009 | op_bne | SW_disassembler.asm:66 33 | $000A | am_absolute_y | SW_disassembler.asm:140 34 | $000A | asciilf | MOS_monitor.asm:8 35 | $000A | cr | SW_disassembler.asm:47 36 | $000A | k_tmp1 | MIOS_defines.asm:58 37 | $000A | line_end | MIOS_defines.asm:73 38 | $000A | op_bpl | SW_disassembler.asm:67 39 | $000B | am_indirect | SW_disassembler.asm:141 40 | $000B | k_tmp2 | MIOS_defines.asm:59 41 | $000B | op_brk | SW_disassembler.asm:68 42 | $000C | am_indexed_indirect | SW_disassembler.asm:142 43 | $000C | k_tmp3 | MIOS_defines.asm:60 44 | $000C | op_bvc | SW_disassembler.asm:69 45 | $000D | am_indirect_indexed | SW_disassembler.asm:143 46 | $000D | asciicr | MOS_monitor.asm:9 47 | $000D | k_tmp4 | MIOS_defines.asm:61 48 | $000D | op_bvs | SW_disassembler.asm:70 49 | $000E | am_indirect_zeropage | SW_disassembler.asm:144 50 | $000E | k_tmp5 | MIOS_defines.asm:62 51 | $000E | op_clc | SW_disassembler.asm:71 52 | $000F | am_absolute_indexed_indirect | SW_disassembler.asm:145 53 | $000F | k_buf_p | MIOS_defines.asm:67 54 | $000F | op_cld | SW_disassembler.asm:72 55 | $0010 | k_buffer | MIOS_defines.asm:68 56 | $0010 | op_cli | SW_disassembler.asm:73 57 | $0011 | op_clv | SW_disassembler.asm:74 58 | $0012 | op_cmp | SW_disassembler.asm:75 59 | $0013 | op_cpx | SW_disassembler.asm:76 60 | $0014 | op_cpy | SW_disassembler.asm:77 61 | $0015 | acia_mode | MIOS_defines.asm:33 62 | $0015 | op_dec | SW_disassembler.asm:78 63 | $0016 | op_dex | SW_disassembler.asm:79 64 | $0017 | op_dey | SW_disassembler.asm:80 65 | $0018 | op_eor | SW_disassembler.asm:81 66 | $0019 | op_inc | SW_disassembler.asm:82 67 | $001A | op_inx | SW_disassembler.asm:83 68 | $001B | esc | SW_disassembler.asm:49 69 | $001B | op_iny | SW_disassembler.asm:84 70 | $001C | op_jmp | SW_disassembler.asm:85 71 | $001D | op_jsr | SW_disassembler.asm:86 72 | $001E | op_lda | SW_disassembler.asm:87 73 | $001F | op_ldx | SW_disassembler.asm:88 74 | $0020 | asciisp | MOS_monitor.asm:10 75 | $0020 | k_buf_len | MIOS_defines.asm:69 76 | $0020 | op_ldy | SW_disassembler.asm:89 77 | $0020 | sp | SW_disassembler.asm:48 78 | $0021 | op_lsr | SW_disassembler.asm:90 79 | $0022 | op_nop | SW_disassembler.asm:91 80 | $0023 | op_ora | SW_disassembler.asm:92 81 | $0024 | op_pha | SW_disassembler.asm:93 82 | $0025 | op_php | SW_disassembler.asm:94 83 | $0026 | op_pla | SW_disassembler.asm:95 84 | $0027 | op_plp | SW_disassembler.asm:96 85 | $0028 | op_rol | SW_disassembler.asm:97 86 | $0029 | op_ror | SW_disassembler.asm:98 87 | $002A | op_rti | SW_disassembler.asm:99 88 | $002B | op_rts | SW_disassembler.asm:100 89 | $002C | op_sbc | SW_disassembler.asm:101 90 | $002D | asciids | MOS_monitor.asm:11 91 | $002D | op_sec | SW_disassembler.asm:102 92 | $002E | op_sed | SW_disassembler.asm:103 93 | $002F | op_sei | SW_disassembler.asm:104 94 | $0030 | op_sta | SW_disassembler.asm:105 95 | $0031 | op_stx | SW_disassembler.asm:106 96 | $0032 | op_sty | SW_disassembler.asm:107 97 | $0033 | op_tax | SW_disassembler.asm:108 98 | $0034 | op_tay | SW_disassembler.asm:109 99 | $0035 | op_tsx | SW_disassembler.asm:110 100 | $0035 | t1 | SW_disassembler.asm:150 101 | $0036 | op_txa | SW_disassembler.asm:111 102 | $0036 | t2 | SW_disassembler.asm:151 103 | $0037 | op_txs | SW_disassembler.asm:112 104 | $0038 | op_tya | SW_disassembler.asm:113 105 | $0039 | op_bbr | SW_disassembler.asm:114 106 | $0039 | opcode | SW_disassembler.asm:153 107 | $003A | op | SW_disassembler.asm:154 108 | $003A | op_bbs | SW_disassembler.asm:115 109 | $003B | op_bra | SW_disassembler.asm:116 110 | $003C | op_phx | SW_disassembler.asm:117 111 | $003D | op_phy | SW_disassembler.asm:118 112 | $003E | op_plx | SW_disassembler.asm:119 113 | $003F | op_ply | SW_disassembler.asm:120 114 | $0040 | op_rmb | SW_disassembler.asm:121 115 | $0041 | am | SW_disassembler.asm:155 116 | $0041 | op_smb | SW_disassembler.asm:122 117 | $0042 | len | SW_disassembler.asm:156 118 | $0042 | op_stz | SW_disassembler.asm:123 119 | $0043 | op_trb | SW_disassembler.asm:124 120 | $0043 | rel | SW_disassembler.asm:157 121 | $0044 | op_tsb | SW_disassembler.asm:125 122 | $0045 | dest | SW_disassembler.asm:158 123 | $0045 | op_stp | SW_disassembler.asm:126 124 | $0046 | op_wai | SW_disassembler.asm:127 125 | $0050 | board | SW_chess.asm:42 126 | $0050 | operand | SW_assembler.asm:60 127 | $0052 | amnem | SW_assembler.asm:61 128 | $0060 | bk | SW_chess.asm:43 129 | $007F | asciidel | MOS_monitor.asm:12 130 | $0080 | at | SW_vtl2a.asm:118 131 | $00B0 | piece | SW_chess.asm:44 132 | $00B1 | square | SW_chess.asm:45 133 | $00B2 | sp2 | SW_chess.asm:46 134 | $00B3 | sp1 | SW_chess.asm:47 135 | $00B4 | inchek | SW_chess.asm:48 136 | $00B5 | state | SW_chess.asm:49 137 | $00B6 | moven | SW_chess.asm:50 138 | $00B7 | rev | SW_chess.asm:51 139 | $00BE | under | SW_vtl2a.asm:122 140 | $00C2 | bang | SW_vtl2a.asm:124 141 | $00C4 | quote | SW_vtl2a.asm:125 142 | $00C6 | pound | SW_vtl2a.asm:126 143 | $00C8 | dolr | SW_vtl2a.asm:127 144 | $00CA | remn | SW_vtl2a.asm:128 145 | $00CC | ampr | SW_vtl2a.asm:129 146 | $00CE | tick | SW_vtl2a.asm:130 147 | $00D0 | lparen | SW_vtl2a.asm:131 148 | $00D2 | rparen | SW_vtl2a.asm:132 149 | $00D4 | star | SW_vtl2a.asm:133 150 | $00DC | omove | SW_chess.asm:52 151 | $00DD | wcap0 | SW_chess.asm:53 152 | $00DE | bcap2 | SW_chess.asm:55 153 | $00DE | count | SW_chess.asm:54 154 | $00DF | wcap2 | SW_chess.asm:56 155 | $00E0 | arg | SW_vtl2a.asm:136 156 | $00E0 | bcap1 | SW_chess.asm:57 157 | $00E1 | wcap1 | SW_chess.asm:58 158 | $00E2 | bcap0 | SW_chess.asm:59 159 | $00E3 | bmob | SW_chess.asm:64 160 | $00E3 | mob | SW_chess.asm:60 161 | $00E4 | bmaxc | SW_chess.asm:65 162 | $00E4 | maxc | SW_chess.asm:61 163 | $00E5 | bmcc | SW_chess.asm:66 164 | $00E5 | cc | SW_chess.asm:62 165 | $00E6 | bmaxp | SW_chess.asm:67 166 | $00E6 | pcap | SW_chess.asm:63 167 | $00E8 | xmaxc | SW_chess.asm:68 168 | $00EB | wmob | SW_chess.asm:69 169 | $00EC | wmaxc | SW_chess.asm:70 170 | $00ED | wcc | SW_chess.asm:71 171 | $00EE | wmaxp | SW_chess.asm:72 172 | $00EF | pmob | SW_chess.asm:73 173 | $00F0 | pmaxc | SW_chess.asm:74 174 | $00F1 | pcc | SW_chess.asm:75 175 | $00F2 | pcp | SW_chess.asm:76 176 | $00F3 | oldky | SW_chess.asm:77 177 | $00F9 | bestm | SW_chess.asm:80 178 | $00F9 | dis3 | SW_chess.asm:83 179 | $00FA | bestv | SW_chess.asm:79 180 | $00FA | dis2 | SW_chess.asm:82 181 | $00FB | bestp | SW_chess.asm:78 182 | $00FB | dis1 | SW_chess.asm:81 183 | $00FC | gthan | SW_vtl2a.asm:139 184 | $00FC | temp | SW_chess.asm:84 185 | $00FE | ques | SW_vtl2a.asm:140 186 | $00FF | stack_end | MIOS_defines.asm:35 187 | $01FF | nulstk | SW_vtl2a.asm:142 188 | $0200 | linbuf | SW_vtl2a.asm:143 189 | $0400 | prgm | SW_vtl2a.asm:144 190 | $7FFC | soft_nmi | MIOS_defines.asm:39 191 | $7FFE | soft_irq | MIOS_defines.asm:40 192 | $8000 | acia_start | MIOS_defines.asm:31 193 | $8000 | himem | SW_vtl2a.asm:145 194 | $E000 | j_wstr | MIOS_kernel_jmptable.asm:22 195 | $E000 | rom_start | MIOS_defines.asm:37 196 | $E003 | j_wchr | MIOS_kernel_jmptable.asm:23 197 | $E006 | j_rchr | MIOS_kernel_jmptable.asm:24 198 | $E009 | j_a2b | MIOS_kernel_jmptable.asm:25 199 | $E00C | j_bin8out | MIOS_kernel_jmptable.asm:26 200 | $E00F | j_hex8out | MIOS_kernel_jmptable.asm:27 201 | $E012 | j_hex4out | MIOS_kernel_jmptable.asm:28 202 | $E015 | j_chr2nibble | MIOS_kernel_jmptable.asm:29 203 | $E018 | m_start | MOS_monitor.asm:20 204 | $E018 | mousestart | MOS_main.asm:24 205 | $E023 | m_main | MOS_monitor.asm:22 206 | $E029 | _wait | MOS_monitor.asm:27 207 | $E047 | m_parse | MOS_monitor.asm:43 208 | $E04B | * | MOS_monitor.asm:47 209 | $E078 | m_cmdjmp | MOS_monitor.asm:63 210 | $E094 | m_parse_end | MOS_monitor.asm:74 211 | $E097 | m_cmd_num | MOS_monitor.asm:79 212 | $E098 | m_cmd_list | MOS_monitor.asm:81 213 | $E0A4 | m_cmd_jumptable | MOS_monitor.asm:84 214 | $E0BC | m_cmd_chess | MOS_monitor.asm:99 215 | $E0BF | m_cmd_vtl2 | MOS_monitor.asm:102 216 | $E0C2 | m_cmd_reset | MOS_monitor.asm:105 217 | $E0C5 | m_cmd_show | MOS_monitor.asm:109 218 | $E0EA | m_cmd_memdump | MOS_monitor.asm:125 219 | $E10B | m_cmd_disass | MOS_monitor.asm:139 220 | $E11A | m_cmd_assemble | MOS_monitor.asm:147 221 | $E129 | m_cmd_go | MOS_monitor.asm:155 222 | $E138 | m_cmd_help | MOS_monitor.asm:163 223 | $E151 | m_cmd_input | MOS_monitor.asm:169 224 | $E165 | _start | MOS_monitor.asm:177 225 | $E167 | _wait | MOS_monitor.asm:179 226 | $E198 | _end | MOS_monitor.asm:203 227 | $E19B | m_cmd_output | MOS_monitor.asm:208 228 | $E1B9 | _loop | MOS_monitor.asm:221 229 | $E1D3 | * | MOS_monitor.asm:234 230 | $E1E9 | m_cmd_fill | MOS_monitor.asm:248 231 | $E208 | _loop | MOS_monitor.asm:261 232 | $E216 | m_show_prompt | MOS_monitor.asm:274 233 | $E222 | m_clear_buffer | MOS_monitor.asm:284 234 | $E229 | * | MOS_monitor.asm:290 235 | $E234 | m_dump_mem | MOS_monitor.asm:310 236 | $E23B | _outer | MOS_monitor.asm:317 237 | $E250 | _inner | MOS_monitor.asm:326 238 | $E266 | * | MOS_monitor.asm:336 239 | $E27D | _inner2 | MOS_monitor.asm:349 240 | $E287 | _next1 | MOS_monitor.asm:355 241 | $E28D | _print | MOS_monitor.asm:358 242 | $E298 | * | MOS_monitor.asm:363 243 | $E2A9 | m_loop_addr | MOS_monitor.asm:388 244 | $E2B0 | * | MOS_monitor.asm:393 245 | $E2C0 | _end | MOS_monitor.asm:401 246 | $E2C1 | _end2 | MOS_monitor.asm:403 247 | $E2C3 | ms_prompt | MOS_monitor.asm:409 248 | $E2C6 | ms_welcome | MOS_monitor.asm:410 249 | $E2D8 | ms_cmd_error | MOS_monitor.asm:411 250 | $E2EC | ms_ok | MOS_monitor.asm:412 251 | $E2F0 | ms_help1 | MOS_monitor.asm:413 252 | $E3EF | ms_help2 | MOS_monitor.asm:414 253 | $E4CD | v_startx | SW_vtl2a.asm:158 254 | $E4DE | startok | SW_vtl2a.asm:168 255 | $E4DF | start | SW_vtl2a.asm:173 256 | $E4F4 | user | SW_vtl2a.asm:183 257 | $E4FE | eloop | SW_vtl2a.asm:192 258 | $E50E | eloop2 | SW_vtl2a.asm:202 259 | $E51D | branch | SW_vtl2a.asm:211 260 | $E525 | branch2 | SW_vtl2a.asm:217 261 | $E529 | xloop | SW_vtl2a.asm:220 262 | $E52F | stmnt | SW_vtl2a.asm:227 263 | $E536 | list_ | SW_vtl2a.asm:237 264 | $E54B | skp2 | SW_vtl2a.asm:252 265 | $E56C | delt | SW_vtl2a.asm:272 266 | $E574 | delt2 | SW_vtl2a.asm:277 267 | $E58A | insrt | SW_vtl2a.asm:289 268 | $E594 | cntln | SW_vtl2a.asm:297 269 | $E5B6 | slide | SW_vtl2a.asm:318 270 | $E5BC | slide2 | SW_vtl2a.asm:322 271 | $E5CE | move | SW_vtl2a.asm:332 272 | $E5D0 | move2 | SW_vtl2a.asm:335 273 | $E5E3 | jstart | SW_vtl2a.asm:347 274 | $E5E6 | findln | SW_vtl2a.asm:359 275 | $E5F4 | prstr | SW_vtl2a.asm:371 276 | $E5F6 | prmsg | SW_vtl2a.asm:388 277 | $E605 | prmsg2 | SW_vtl2a.asm:397 278 | $E60F | prpause | SW_vtl2a.asm:405 279 | $E618 | prout | SW_vtl2a.asm:412 280 | $E622 | outcr | SW_vtl2a.asm:419 281 | $E626 | inch | SW_vtl2a.asm:425 282 | $E631 | outch | SW_vtl2a.asm:470 283 | $E631 | skip_cr | SW_vtl2a.asm:478 284 | $E634 | outrts | SW_vtl2a.asm:489 285 | $E635 | exec | SW_vtl2a.asm:504 286 | $E647 | exec1 | SW_vtl2a.asm:514 287 | $E669 | exec2 | SW_vtl2a.asm:532 288 | $E66D | exec3 | SW_vtl2a.asm:535 289 | $E681 | execrts | SW_vtl2a.asm:548 290 | $E682 | prstr_x | SW_vtl2a.asm:550 291 | $E685 | prnum0 | SW_vtl2a.asm:555 292 | $E687 | prnum | SW_vtl2a.asm:563 293 | $E696 | prnum2 | SW_vtl2a.asm:573 294 | $E6A5 | prnum3 | SW_vtl2a.asm:582 295 | $E6B2 | eval | SW_vtl2a.asm:606 296 | $E6BA | notdn | SW_vtl2a.asm:611 297 | $E6CF | evalrts | SW_vtl2a.asm:625 298 | $E6D0 | getval | SW_vtl2a.asm:631 299 | $E6F3 | getval2 | SW_vtl2a.asm:653 300 | $E6FD | getval3 | SW_vtl2a.asm:659 301 | $E70D | getval4 | SW_vtl2a.asm:668 302 | $E714 | getrts | SW_vtl2a.asm:673 303 | $E715 | oper | SW_vtl2a.asm:680 304 | $E719 | add | SW_vtl2a.asm:684 305 | $E727 | oper2 | SW_vtl2a.asm:693 306 | $E72B | sub | SW_vtl2a.asm:697 307 | $E739 | oper3 | SW_vtl2a.asm:706 308 | $E73D | mul | SW_vtl2a.asm:714 309 | $E74B | mul2 | SW_vtl2a.asm:722 310 | $E754 | mul3 | SW_vtl2a.asm:727 311 | $E75F | oper4 | SW_vtl2a.asm:734 312 | $E763 | div | SW_vtl2a.asm:742 313 | $E76D | div1 | SW_vtl2a.asm:748 314 | $E789 | div2 | SW_vtl2a.asm:763 315 | $E78E | oper5 | SW_vtl2a.asm:772 316 | $E79E | oper5a | SW_vtl2a.asm:781 317 | $E79F | oper5b | SW_vtl2a.asm:783 318 | $E7A8 | oper5c | SW_vtl2a.asm:789 319 | $E7A9 | oper5d | SW_vtl2a.asm:791 320 | $E7B0 | convp | SW_vtl2a.asm:805 321 | $E7B9 | varray | SW_vtl2a.asm:811 322 | $E7CB | cvbin | SW_vtl2a.asm:829 323 | $E7D5 | cvbin2 | SW_vtl2a.asm:835 324 | $E7F0 | cvbin3 | SW_vtl2a.asm:850 325 | $E7F3 | inln6 | SW_vtl2a.asm:860 326 | $E7FA | newln | SW_vtl2a.asm:866 327 | $E7FD | inln | SW_vtl2a.asm:868 328 | $E807 | inln5 | SW_vtl2a.asm:874 329 | $E80A | inln2 | SW_vtl2a.asm:877 330 | $E81A | inln3 | SW_vtl2a.asm:886 331 | $E820 | find | SW_vtl2a.asm:900 332 | $E82A | findnxt | SW_vtl2a.asm:906 333 | $E833 | find1st | SW_vtl2a.asm:911 334 | $E839 | getlpar | SW_vtl2a.asm:915 335 | $E84A | checkat | SW_vtl2a.asm:925 336 | $E854 | findrts | SW_vtl2a.asm:931 337 | $E859 | chess | SW_chess.asm:93 338 | $E861 | out | SW_chess.asm:103 339 | $E86D | whset | SW_chess.asm:112 340 | $E87D | noset | SW_chess.asm:121 341 | $E88F | norev | SW_chess.asm:131 342 | $E896 | cldsp | SW_chess.asm:134 343 | $E89E | nogo | SW_chess.asm:139 344 | $E8A8 | nomv | SW_chess.asm:143 345 | $E8AF | done | SW_chess.asm:146 346 | $E8B2 | janus | SW_chess.asm:155 347 | $E8B6 | counts | SW_chess.asm:162 348 | $E8C2 | over | SW_chess.asm:169 349 | $E8CA | noq | SW_chess.asm:174 350 | $E8D0 | elooop | SW_chess.asm:177 351 | $E8D8 | foun | SW_chess.asm:181 352 | $E8E3 | less | SW_chess.asm:187 353 | $E8EA | nocap | SW_chess.asm:193 354 | $E8F0 | xrt | SW_chess.asm:196 355 | $E8F1 | on4 | SW_chess.asm:201 356 | $E90F | nocount | SW_chess.asm:216 357 | $E91D | retj | SW_chess.asm:227 358 | $E91E | tree | SW_chess.asm:233 359 | $E924 | loopx | SW_chess.asm:236 360 | $E92E | founx | SW_chess.asm:241 361 | $E937 | nomax | SW_chess.asm:245 362 | $E942 | uptree | SW_chess.asm:250 363 | $E945 | input | SW_chess.asm:255 364 | $E94C | disp | SW_chess.asm:258 365 | $E94E | search | SW_chess.asm:259 366 | $E957 | here | SW_chess.asm:264 367 | $E95B | error | SW_chess.asm:266 368 | $E95E | gnmz | SW_chess.asm:273 369 | $E960 | gnmx | SW_chess.asm:274 370 | $E962 | clear | SW_chess.asm:275 371 | $E967 | gnm | SW_chess.asm:279 372 | $E96B | newp | SW_chess.asm:281 373 | $E970 | nex | SW_chess.asm:285 374 | $E98B | king | SW_chess.asm:299 375 | $E992 | queen | SW_chess.asm:302 376 | $E999 | rook | SW_chess.asm:306 377 | $E99D | agnr | SW_chess.asm:308 378 | $E9A4 | bishop | SW_chess.asm:312 379 | $E9AF | knight | SW_chess.asm:318 380 | $E9B3 | agnn | SW_chess.asm:320 381 | $E9BE | pawn | SW_chess.asm:326 382 | $E9C2 | p1 | SW_chess.asm:328 383 | $E9CC | p2 | SW_chess.asm:332 384 | $E9D7 | p3 | SW_chess.asm:337 385 | $E9EC | sngmv | SW_chess.asm:350 386 | $E9F4 | ill1 | SW_chess.asm:353 387 | $E9FA | line | SW_chess.asm:360 388 | $EA01 | ovl | SW_chess.asm:363 389 | $EA0A | ill | SW_chess.asm:368 390 | $EA10 | reverse | SW_chess.asm:375 391 | $EA12 | etc | SW_chess.asm:376 392 | $EA28 | cmove | SW_chess.asm:400 393 | $EA3A | loop | SW_chess.asm:410 394 | $EA4B | no | SW_chess.asm:422 395 | $EA4C | spx | SW_chess.asm:424 396 | $EA54 | chkchk | SW_chess.asm:437 397 | $EA74 | retl | SW_chess.asm:455 398 | $EA78 | illegal | SW_chess.asm:459 399 | $EA7D | reset | SW_chess.asm:466 400 | $EA84 | genrm | SW_chess.asm:473 401 | $EA87 | genr2 | SW_chess.asm:474 402 | $EA8D | rum | SW_chess.asm:476 403 | $EA90 | umove | SW_chess.asm:481 404 | $EAAA | movexx | SW_chess.asm:504 405 | $EAB6 | check | SW_chess.asm:512 406 | $EABD | take | SW_chess.asm:516 407 | $EACF | strv | SW_chess.asm:528 408 | $EAD6 | ckmate | SW_chess.asm:538 409 | $EAE1 | nochek | SW_chess.asm:544 410 | $EAEB | retv | SW_chess.asm:550 411 | $EAEF | push | SW_chess.asm:557 412 | $EAFF | retp | SW_chess.asm:565 413 | $EB04 | go | SW_chess.asm:571 414 | $EB20 | end | SW_chess.asm:586 415 | $EB24 | noopen | SW_chess.asm:588 416 | $EB3C | mv2 | SW_chess.asm:604 417 | $EB4E | mate | SW_chess.asm:613 418 | $EB51 | dismv | SW_chess.asm:619 419 | $EB53 | drol | SW_chess.asm:620 420 | $EB61 | stratgy | SW_chess.asm:635 421 | $EB81 | pos | SW_chess.asm:652 422 | $EBC1 | posn | SW_chess.asm:687 423 | $EBC4 | noposn | SW_chess.asm:689 424 | $EBC7 | pout | SW_chess.asm:696 425 | $EBD5 | pout1 | SW_chess.asm:701 426 | $EBDC | pout2 | SW_chess.asm:704 427 | $EBFA | pout25 | SW_chess.asm:724 428 | $EC02 | pout3 | SW_chess.asm:727 429 | $EC21 | pout4 | SW_chess.asm:744 430 | $EC2A | pout41 | SW_chess.asm:748 431 | $EC2D | pout42 | SW_chess.asm:749 432 | $EC38 | pout5 | SW_chess.asm:754 433 | $EC3E | pout6 | SW_chess.asm:758 434 | $EC4A | pout8 | SW_chess.asm:766 435 | $EC66 | pout9 | SW_chess.asm:778 436 | $EC6C | pout10 | SW_chess.asm:784 437 | $EC6E | pout11 | SW_chess.asm:785 438 | $EC7E | pout12 | SW_chess.asm:793 439 | $EC85 | pout13 | SW_chess.asm:798 440 | $EC87 | pout14 | SW_chess.asm:799 441 | $EC92 | pout15 | SW_chess.asm:804 442 | $EC93 | kin | SW_chess.asm:806 443 | $EC9E | syskin | SW_chess.asm:812 444 | $ECA4 | syschout | SW_chess.asm:815 445 | $ECA8 | syshexout | SW_chess.asm:817 446 | $ECAC | banner | SW_chess.asm:823 447 | $ECE8 | cpl | SW_chess.asm:825 448 | $ED18 | cph | SW_chess.asm:826 449 | $ED39 | setw | SW_chess.asm:833 450 | $ED59 | movex | SW_chess.asm:838 451 | $ED6A | points | SW_chess.asm:841 452 | $ED7A | opning | SW_chess.asm:844 453 | $F005 | dstart | SW_disassembler.asm:164 454 | $F005 | outer | SW_disassembler.asm:165 455 | $F00C | dloop | SW_disassembler.asm:168 456 | $F021 | spaceorescape | SW_disassembler.asm:176 457 | $F02F | disasm | SW_disassembler.asm:187 458 | $F047 | upper | SW_disassembler.asm:200 459 | $F054 | around | SW_disassembler.asm:208 460 | $F086 | two | SW_disassembler.asm:231 461 | $F098 | three | SW_disassembler.asm:239 462 | $F0AF | one | SW_disassembler.asm:249 463 | $F0BD | mnem | SW_disassembler.asm:259 464 | $F0D1 | domb | SW_disassembler.asm:271 465 | $F0EE | trybb | SW_disassembler.asm:286 466 | $F0F8 | dobb | SW_disassembler.asm:292 467 | $F126 | _dneg | SW_disassembler.asm:317 468 | $F128 | _dadd | SW_disassembler.asm:319 469 | $F14F | tryimp | SW_disassembler.asm:339 470 | $F158 | tryinv | SW_disassembler.asm:344 471 | $F15F | tryacc | SW_disassembler.asm:348 472 | $F170 | tryimm | SW_disassembler.asm:358 473 | $F186 | tryzp | SW_disassembler.asm:368 474 | $F197 | tryzpx | SW_disassembler.asm:376 475 | $F1AB | tryzpy | SW_disassembler.asm:385 476 | $F1BF | tryrel | SW_disassembler.asm:394 477 | $F1D2 | neg | SW_disassembler.asm:406 478 | $F1D4 | dadd | SW_disassembler.asm:408 479 | $F1FB | tryabs | SW_disassembler.asm:428 480 | $F213 | tryabsx | SW_disassembler.asm:439 481 | $F22E | tryabsy | SW_disassembler.asm:451 482 | $F249 | tryind | SW_disassembler.asm:463 483 | $F264 | tryindxind | SW_disassembler.asm:475 484 | $F27B | tryindindx | SW_disassembler.asm:485 485 | $F292 | tryindz | SW_disassembler.asm:495 486 | $F2A6 | tryabindind | SW_disassembler.asm:504 487 | $F2C4 | doneops | SW_disassembler.asm:517 488 | $F2D7 | printdollar | SW_disassembler.asm:533 489 | $F2DF | printcommax | SW_disassembler.asm:542 490 | $F2EC | printcommay | SW_disassembler.asm:553 491 | $F2F9 | printlparendollar | SW_disassembler.asm:564 492 | $F306 | printrparen | SW_disassembler.asm:575 493 | $F30E | printcr | SW_disassembler.asm:584 494 | $F316 | printspace | SW_disassembler.asm:593 495 | $F31E | printspaces | SW_disassembler.asm:602 496 | $F321 | * | SW_disassembler.asm:605 497 | $F329 | getkey | SW_disassembler.asm:615 498 | $F331 | printaddress | SW_disassembler.asm:624 499 | $F33E | printbyte | SW_disassembler.asm:636 500 | $F344 | mnemonics | SW_disassembler.asm:653 501 | $F419 | lengths | SW_disassembler.asm:728 502 | $F419 | mnemonicsend | SW_disassembler.asm:725 503 | $F429 | opcodes | SW_disassembler.asm:734 504 | $F429 | opcodes1 | SW_disassembler.asm:735 505 | $F529 | opcodes2 | SW_disassembler.asm:872 506 | $F629 | continuestring | SW_disassembler.asm:1011 507 | $F64E | astart | SW_assembler.asm:63 508 | $F653 | assembleline | SW_assembler.asm:65 509 | $F660 | getmnem | SW_assembler.asm:74 510 | $F693 | escpressed | SW_assembler.asm:97 511 | $F696 | opok | SW_assembler.asm:102 512 | $F6A2 | getoperands | SW_assembler.asm:111 513 | $F6C0 | atryimm | SW_assembler.asm:133 514 | $F6EA | tryzeropage | SW_assembler.asm:156 515 | $F70E | tryabsrel | SW_assembler.asm:177 516 | $F739 | save2operands | SW_assembler.asm:202 517 | $F74E | tryrelative | SW_assembler.asm:213 518 | $F75A | tryzeropagex | SW_assembler.asm:223 519 | $F78D | tryzeropagey | SW_assembler.asm:250 520 | $F7C0 | tryabsolutex | SW_assembler.asm:277 521 | $F80A | tryabsolutey | SW_assembler.asm:314 522 | $F854 | tryindexedindirect | SW_assembler.asm:350 523 | $F893 | tryindirectindexed | SW_assembler.asm:382 524 | $F8D2 | tryindirect | SW_assembler.asm:415 525 | $F919 | tryindirectzp | SW_assembler.asm:451 526 | $F949 | tryabsindind | SW_assembler.asm:477 527 | $F99F | invalidop | SW_assembler.asm:521 528 | $F9B0 | generatecode | SW_assembler.asm:526 529 | $F9C6 | operandokay | SW_assembler.asm:536 530 | $F9EC | writeoperands | SW_assembler.asm:565 531 | $F9F5 | atryacc | SW_assembler.asm:570 532 | $F9FC | atryimmed | SW_assembler.asm:575 533 | $FA03 | atryzp | SW_assembler.asm:579 534 | $FA0A | atryzpx | SW_assembler.asm:582 535 | $FA11 | atryzpy | SW_assembler.asm:585 536 | $FA39 | relative | SW_assembler.asm:613 537 | $FA5B | outofrange | SW_assembler.asm:637 538 | $FA69 | okayzero | SW_assembler.asm:641 539 | $FA70 | okayff | SW_assembler.asm:646 540 | $FA74 | oneoperand | SW_assembler.asm:652 541 | $FA7D | twooperands | SW_assembler.asm:658 542 | $FA88 | zerooperands | SW_assembler.asm:666 543 | $FA98 | lookupmnemonic | SW_assembler.asm:682 544 | $FAA2 | aloop | SW_assembler.asm:688 545 | $FABE | nextop | SW_assembler.asm:706 546 | $FADD | checkaddressingmodevalid | SW_assembler.asm:735 547 | $FAE7 | opaloop | SW_assembler.asm:741 548 | $FAFC | nextinst | SW_assembler.asm:757 549 | $FB0F | opnotfound | SW_assembler.asm:769 550 | $FB12 | ishexdigit | SW_assembler.asm:777 551 | $FB25 | @invalid | SW_assembler.asm:787 552 | $FB28 | @okay | SW_assembler.asm:790 553 | $FB2B | twocharstobin | SW_assembler.asm:799 554 | $FB3D | chartobin | SW_assembler.asm:817 555 | $FB48 | @digit | SW_assembler.asm:824 556 | $FB4C | toupper | SW_assembler.asm:830 557 | $FB56 | @notlower | SW_assembler.asm:836 558 | $FB57 | getline | SW_assembler.asm:839 559 | $FB59 | glloop | SW_assembler.asm:841 560 | $FB6F | next | SW_assembler.asm:852 561 | $FB72 | filter | SW_assembler.asm:858 562 | $FB7C | charokay | SW_assembler.asm:865 563 | $FB88 | enterpressed | SW_assembler.asm:872 564 | $FB89 | escapepressed | SW_assembler.asm:874 565 | $FB90 | filterchars | SW_assembler.asm:880 566 | $FBAF | invalidinstruction | SW_assembler.asm:884 567 | $FBC3 | invalidoperand | SW_assembler.asm:887 568 | $FBD3 | invalidaddressmode | SW_assembler.asm:890 569 | $FBEB | unabletowrite | SW_assembler.asm:893 570 | $FC00 | branchouofrange | SW_assembler.asm:896 571 | $FC1D | no65c02allowed | SW_assembler.asm:899 572 | $FC3B | acia_init | MIOS_driver_ACIApy65mon.asm:20 573 | $FC3C | acia_send_b | MIOS_driver_ACIApy65mon.asm:33 574 | $FC40 | acia_send | MIOS_driver_ACIApy65mon.asm:48 575 | $FC44 | acia_ready2send | MIOS_driver_ACIApy65mon.asm:63 576 | $FC47 | acia_received | MIOS_driver_ACIApy65mon.asm:78 577 | $FC4A | acia_receive_b | MIOS_driver_ACIApy65mon.asm:93 578 | $FC50 | acia_receive | MIOS_driver_ACIApy65mon.asm:108 579 | $FC54 | k_start | MIOS_kernel.asm:34 580 | $FC63 | u_bin8out | MIOS_kernel.asm:56 581 | $FC65 | _loop | MIOS_kernel.asm:58 582 | $FC6C | _p0 | MIOS_kernel.asm:63 583 | $FC76 | u_hex8out | MIOS_kernel.asm:82 584 | $FC83 | u_hex4out | MIOS_kernel.asm:106 585 | $FC91 | u_hexdigit | MIOS_kernel.asm:115 586 | $FCA1 | u_chr2nibble | MIOS_kernel.asm:131 587 | $FCB2 | * | MIOS_kernel.asm:142 588 | $FCB3 | k_wstr | MIOS_kernel.asm:161 589 | $FCB8 | * | MIOS_kernel.asm:166 590 | $FCC3 | * | MIOS_kernel.asm:171 591 | $FCC7 | k_wchr | MIOS_kernel.asm:188 592 | $FCCB | k_rchr | MIOS_kernel.asm:210 593 | $FCD2 | * | MIOS_kernel.asm:223 594 | $FCD3 | * | MIOS_kernel.asm:242 595 | $FCD3 | k_ascii2byte | MIOS_kernel.asm:231 596 | $FCEC | k_reset | MIOS_kernel.asm:269 597 | $FCF3 | * | MIOS_kernel.asm:276 598 | $FD15 | k_nmi | MIOS_kernel.asm:310 599 | $FD18 | k_nmi_end | MIOS_kernel.asm:312 600 | $FD19 | k_irq | MIOS_kernel.asm:324 601 | $FD1C | k_irq_end | MIOS_kernel.asm:326 602 | $FD1D | k_welcome | MIOS_kernel.asm:341 603 | $FFF8 | aciaout | MIOS_driver_ACIApy65mon.asm:11 604 | $FFF9 | aciain | MIOS_driver_ACIApy65mon.asm:9 605 | --------------------------------------------------------------------------------