// main_msx1_jp.oc: Ocala port of main_msx1_jp.asm
// GENERATED BY ocalaconv
// -- doc: cbios.txt
/* ************************************************************************* **
C-BIOS 0.29
===========
This software is a substitute BIOS which is can be used for running MSX
emulators. It currently supports only execution of cartridge image ("ROMs").
Before you use it, you should read and accept the license (see below).
On the C-BIOS web site, you can download newer versions, download the source
code, and report bugs.
http://cbios.sourceforge.net/
License
-------
Copyright (c) 2002-2005 BouKiCHi. All rights reserved.
Copyright (c) 2003 Reikan. All rights reserved.
Copyright (c) 2004-2006,2008-2010 Maarten ter Huurne. All rights reserved.
Copyright (c) 2004-2006,2008-2011 Albert Beevendorp. All rights reserved.
Copyright (c) 2004-2005 Patrick van Arkel. All rights reserved.
Copyright (c) 2004,2010-2011 Manuel Bilderbeek. All rights reserved.
Copyright (c) 2004-2006 Joost Yervante Damad. All rights reserved.
Copyright (c) 2004-2006 Jussi Pitkänen. All rights reserved.
Copyright (c) 2004-2007 Eric Boon. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
History
-------
ver 0.01 Initial
ver 0.02 2002-08-15(JST)
* Added original font and drawing screen.
* Added dump-mode.
* Changed recognition method of cartridges
to recognize cartridges taking priority.
ver 0.03 2002-08-19(JST)
* Based on a suggestion from Ms.Okei,
wrote 20h of BIOS(compare HL and DE).
In the result, shooting game of a certain company became runnable
more correctly.
Thank Ms.Okei!!
ver 0.04 2002-08-20(JST)
* Added initialize of FCC2h-FCC4h.
* Added function of GTSTCK and GTTRIG temporarily.
* Divided msxb.bin to halfs.
doing combining/copying with setb.bat now.
ver 0.05 2002-08-27(JST)
* Added INITGRP(only screen2), CHGMOD(graphic mode change routine),
a routine calls H.STKE.
* Rewrite memory recognition routine.
* Some bug fixes.
* Added sound test function.
ver 0.06 2002-09-01(JST)
* Fixed around of color.
ver 0.07 2002-09-09(JST)
* Added some sorts of keyboard routines.
* Added joystich function to GTSTCK and GTTRIG.
ver 0.08 2002-09-12(JST)
* Restructured memory initialize routine.
* Added error display routine.
* Fixed routine of finding kinds of cartridges.
* Fixed using method of EXPTBL.
* Added initialize of from RG8SAV to RG23SA.
* Now return within disabled interrupt from ENASLT routine.
ver 0.09 2002-09-19(JST)
* Made the rest half of font.
* Improved key input routine.
* Added CHPUT. With it, rewrote display routine.
* Fixed init_grp.
* Changed filenames to CBIOS.ROM, CBIOS_SUB.ROM.
ver 0.10 2002-09-20(JST)
* Fixed indent.
* and so on...
ver 0.10a 2002-09-22(JST)
* Fixed license.
* Added support of ROMs in page3.
ver 0.11 2002-09-22(JST)
* Small fix in init_sc5.
ver 0.12beta
2002-09-25(JST)
* Added test routine for disk access. need DISK.ROM.
* Added init_sc7.
* Improved ENASLT. now finding cartridge uses ENASLT.
* Improved RAM detection.
ver 0.12 2002-09-27(JST)
* Changed finding cartridge again.
* Changed screen mode of cartridge running time.
* Fixed keyboard routine.
* Fixed stick routine against to interrupt.
ver 0.13 2002-10-02(JST)
* Based on info from Mr.Maarten (a member of openMSX developers),
fixed around of SCREEN 5.
For detail, switching line numbers,
temporary treatment for a bug of reading from VDP status register,
and so on.
ver 0.14 2002-10-10(JST)
* Rewrote comments in source within Japanese.
ver 0.15 2003-02-26(JST)
* Rewrote some of comments back to English again.
* Fixed non-assemblable condition becauseof lack of font file.
* Changed filename, some of label name, strings and so on.
ver 0.16 2003-04-16(JST)
* Separated sound test from source. (Disabled)
ver 0.16a 2003-06-01(JST)
* CHGMOD: When screen0/1, now load font to VRAM.
* CHPUT: Now support also screen1 not only screen0.
ver 0.16b 2003-08-10(JST)
* Added entry: INITXT, INIT32.
These were exist only as internal routine of CHGMOD.
* INITXT, INIT32: Fixed screen clear failure.
* CHPUT: Fixed scroll failure.
ver 0.17 2003-08-10(JST)
* Changed LICENSE.
New LICENSE will be suitable in various situations.
e.g. use as a firmware for hand-made hardware.
ver 0.18 2004-12-18(CET)
* First release since moving to SourceForge.
* Much improved support for MSX2 games.
* Graphical boot logo.
* Included machine config files for several MSX emulators.
* Various bug fixes.
ver 0.19 2004-12-24(CET)
* Added support for SCREEN4 and SCREEN8.
* Added support for clock chip.
* Added support for palette. This fixes a lot of wrong colours.
* Stubbed many calls: non-implemented calls print their name on the
openMSX debugdevice (if present).
* Various bug fixes.
ver 0.20 2005-02-09(CET)
* Added an MSX2+ configuration, which includes V9958 and MSX MUSIC.
* Separate main ROMs for MSX1/MSX2/MSX2+.
* Implemented several MSX2 specific routines, including BLT*.
* Display is disabled when switching to a different screen mode.
* Improved CHPUT a lot; implemented control and escape codes.
* Rewrote key buffering; fixes bug of keys being repeated.
* New boot logo, even cooler than the previous one.
* New font, placed at a fixed address so all games can find it.
* Started work on a disk ROM, but it is not functional yet, so it
is not enabled in the configurations.
* Stubbed all non-implemented calls.
* Various bug fixes.
ver 0.21 2005-06-07(CET)
* Fixed RuMSX configuration files, thanks to Rudolf Lechleitner.
* Rewrote ROM search code; now all ROMs are recognized.
Also a clear error message is printed for BASIC ROMs.
* New boot logo for MSX2 and MSX2+.
* Changed boot sequence:
Show logo, switch to SCREEN 1 and search for ROMs.
* Improved video code; fixes several games.
* Various bug fixes.
ver 0.22 2008-12-27(CET)
* Use separate logo ROM to save space in the main ROM.
* Set lower bits of PSG reg 15 before reading joystick trigger status.
* Improved RAM search.
* Many new routines implemented and existing implementations made
more complete, especially character I/O and bitmap graphics.
* Added lots of documentation to system variables.
* Added support for GNU assembler.
* Various bug fixes.
ver 0.23 2009-01-04(CET)
* Updated blueMSX configuration files, thanks to Benoît Delvaux.
* Fixed version reported by MSX1 logo ROM.
* Fixed several video routines so they work on MSX1 VDPs (TMS99xx).
* A couple of other bug fixes.
ver 0.24 2010-05-24(CET)
* VRAM size is now properly checked, fixing R-Type's V9938 detection.
* C-BIOS doesn't lie anymore about the interrupt frequency.
* Don't di; halt when no ROM is found, the warning in openMSX may be
confusing
* A few minor bug fixes and tweaks.
ver 0.25 2011-02-01(CET)
* C-BIOS now offers localized versions in the flavours INT (default),
JP and BR.
* Bug fixes for compatibility with Mirai, Family Billiards.
* A couple of other bug fixes.
* This version only compiles with Pasmo 0.5.3, due to lack of
standards in assembler directives...
ver 0.26 2014-11-02(CET)
* Restored support to compile with tniASM (v1.0 Beta 17 or higher)
* Moved to git, which means a.o.: archived changelog.txt, use git log
from now on
* Fixed VDP VRAM access timing for MSX1 VDP's
* Update openMSX configurations to the new structure
* Fixed bug blueMSX configurations
* Fixed build on Mac OS X and add support for "make dist"
ver 0.27 2014-11-05(CET)
* Fixed bug (regression) in filvrm on non-MSX1-VDP's
* Fixed some small bugs in openMSX configs
* Fixed line endings of this file
ver 0.28 2017-07-30(CEST)
* Fixed bug that prevented brackets and a few other keys from
generating characters when pressed
ver 0.29 2018-02-18(CET)
* Removed NLMSX configs. We don't think anyone is interested anymore
* Made generic international ROM config 60Hz and added an EU variant
at 50Hz default interrupt frequency
ver 0.29a 2018-09-23(CEST)
* Fixed metadata in openMSX configs for EU machines
Special Thanks
--------------
People uploading MSX information to the internet.
People developing any kind of emulators.
All users.
Font edit tool:
Gameboy Tile Designer version 2.2
Copyright H. Mulder 1999
** ************************************************************************* */
arch z80
include "z80.oc"
link { org 0 0x8000 LINK/FILL; merge text _ }
macro org>(addr) { fill (%=addr - __PC__) }
struct byteword { b byte ; w word }
flat!
section text ={
// -- begin: main_msx1_jp.asm
// ; C-BIOS main ROM for a Japanese MSX1 machine
// ;
// ; Copyright (c) 2005 Maarten ter Huurne. All rights reserved.
// ; Copyright (c) 2005 Joost Yervante Damad. All rights reserved.
// ; Copyright (C) 2005 BouKiCHi. All rights reserved.
// ; Copyright (C) 2008 Eric Boon. All rights reserved.
// ;
// ; Redistribution and use in source and binary forms, with or without
// ; modification, are permitted provided that the following conditions
// ; are met:
// ; 1. Redistributions of source code must retain the above copyright
// ; notice, this list of conditions and the following disclaimer.
// ; 2. Redistributions in binary form must reproduce the above copyright
// ; notice, this list of conditions and the following disclaimer in the
// ; documentation and/or other materials provided with the distribution.
// ;
// ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ;
// -- begin: hardware.asm
// ; C-BIOS hardware related declarations
// ;
// ; Copyright (c) 2002-2005 BouKiCHi. All rights reserved.
// ; Copyright (c) 2003 Reikan. All rights reserved.
// ; Copyright (c) 2004-2005 Maarten ter Huurne. All rights reserved.
// ; Copyright (c) 2004 Manuel Bilderbeek. All rights reserved.
// ; Copyright (c) 2004-2006 Albert Beevendorp. All rights reserved.
// ; Copyright (c) 2004-2005 Joost Yervante Damad. All rights reserved.
// ;
// ; Redistribution and use in source and binary forms, with or without
// ; modification, are permitted provided that the following conditions
// ; are met:
// ; 1. Redistributions of source code must retain the above copyright
// ; notice, this list of conditions and the following disclaimer.
// ; 2. Redistributions in binary form must reproduce the above copyright
// ; notice, this list of conditions and the following disclaimer in the
// ; documentation and/or other materials provided with the distribution.
// ;
// ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ;
// ;---------------------------------------------------
// ; I/O ports
const DBG_CTRL = 0x2e // ; openMSX debugdevice control (mode)
const DBG_DATA = 0x2f // ; openMSX debugdevice data
const PRN_STAT = 0x90 // ; printer status
const PRN_DATA = 0x91 // ; printer data
const VDP_DATA = 0x98 // ; VDP data port (VRAM read/write)
const VDP_ADDR = 0x99 // ; VDP address (write only)
const VDP_STAT = 0x99 // ; VDP status (read only)
const VDP_PALT = 0x9a // ; VDP palette latch (write only)
const VDP_REGS = 0x9b // ; VDP register access (write only)
const PSG_REGS = 0xa0 // ; PSG register write port
const PSG_DATA = 0xa1 // ; PSG value write port
const PSG_STAT = 0xa2 // ; PSG value read port
const PSL_STAT = 0xa8 // ; slot status
const KBD_STAT = 0xa9 // ; keyboard status
const GIO_REGS = 0xaa // ; General IO Register
const PPI_REGS = 0xab // ; PPI register
const RTC_ADDR = 0xb4 // ; RTC address
const RTC_DATA = 0xb5 // ; RTC data
const SYSFLAGS = 0xf4 // ; MSX2+ System flags,
// ; preserved after reset
// ; bit 5: CPU boot mode (1=R800)
// ; bit 7: Boot method
// ; (1=soft boot, no logo)
const MAP_REG1 = 0xfc // ; memory mapper: bank in $0000-$3FFF
const MAP_REG2 = 0xfd // ; memory mapper: bank in $4000-$7FFF
const MAP_REG3 = 0xfe // ; memory mapper: bank in $8000-$BFFF
const MAP_REG4 = 0xff // ; memory mapper: bank in $C000-$FFFF
// ;---------------------------------------------------
// ; memory mapped I/O
const SSL_REGS = 0xffff // ; secondary slot select registers
// ;---------------------------------------------------
// ; Constants used to define which hardware the BIOS will run on.
// ; Used by the main_<model>.asm sources.
// ; VDP models:
const TMS99X8 = 0x9918
const V9938 = 0x9938
const V9958 = 0x9958
// ; MSX models:
const MODEL_MSX1 = 0
const MODEL_MSX2 = 1
const MODEL_MSX2P = 2
const MODEL_MSXTR = 3
const MODEL_SUBROM = 4
// ; Locales:
// ; -- ID byte 0
const LOCAL_CHSET_JP = 0x00
const LOCAL_CHSET_US = 0x01
const LOCAL_CHSET_KO = 0x02
// ; There are charsets which pretend to be INT, but are not... For now only BR:
const LOCAL_CHSET_VAR_NONE = 0x00
const LOCAL_CHSET_VAR_BR = 0x01
const LOCAL_DATE_YMD = 0x00
const LOCAL_DATE_MDY = 0x10
const LOCAL_DATE_DMY = 0x20
const LOCAL_INT_60HZ = 0x00
const LOCAL_INT_50HZ = 0x80
// ; -- ID byte 1
const LOCAL_KBD_JP = 0x00
const LOCAL_KBD_US = 0x01
const LOCAL_KBD_FR = 0x02
const LOCAL_KBD_UK = 0x03
const LOCAL_KBD_DE = 0x04
const LOCAL_BASIC_JP = 0x00
const LOCAL_BASIC_US = 0x01
// ; BOOLEAN VALUES
const YES = 1
const NO = 0
// ; vim:ts=8:expandtab:filetype=z8a:syntax=z8a:
// -- end: hardware.asm
const VDP = TMS99X8
const MODEL_MSX = MODEL_MSX1
// ; -- japanese config
const LOCALE_CHSET = LOCAL_CHSET_JP
const LOCALE_CHSET_VAR = LOCAL_CHSET_VAR_NONE
const LOCALE_DATE = LOCAL_DATE_YMD
const LOCALE_INT = LOCAL_INT_60HZ
const LOCALE_KBD = LOCAL_KBD_JP
const LOCALE_BASIC = LOCAL_BASIC_JP
const COLOR_FORE = 15
const COLOR_BACK = 4
const COLOR_BORDER = 7
const CALL_SUB = NO
// -- begin: main.asm
// ; C-BIOS main ROM
// ;
// ; Copyright (c) 2002-2005 BouKiCHi. All rights reserved.
// ; Copyright (c) 2003 Reikan. All rights reserved.
// ; Copyright (c) 2004-2005 Maarten ter Huurne. All rights reserved.
// ; Copyright (c) 2004-2009 Albert Beevendorp. All rights reserved.
// ; Copyright (c) 2004 Manuel Bilderbeek. All rights reserved.
// ; Copyright (c) 2004-2005 Joost Yervante Damad. All rights reserved.
// ; Copyright (c) 2004-2005 Jussi Pitkänen. All rights reserved.
// ; Copyright (c) 2006-2007 Eric Boon. All rights reserved.
// ;
// ; Redistribution and use in source and binary forms, with or without
// ; modification, are permitted provided that the following conditions
// ; are met:
// ; 1. Redistributions of source code must retain the above copyright
// ; notice, this list of conditions and the following disclaimer.
// ; 2. Redistributions in binary form must reproduce the above copyright
// ; notice, this list of conditions and the following disclaimer in the
// ; documentation and/or other materials provided with the distribution.
// ;
// ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ;
// -- begin: systemvars.asm
// ;
// ; C-BIOS system variable declarations
// ;
// ; Copyright (c) 2002-2003 BouKiCHi. All rights reserved.
// ; Copyright (c) 2003 Reikan. All rights reserved.
// ; Copyright (c) 2004-2005 Maarten ter Huurne. All rights reserved.
// ; Copyright (c) 2004 Manuel Bilderbeek. All rights reserved.
// ; Copyright (c) 2004-2006 Joost Yervante Damad. All rights reserved.
// ; Copyright (c) 2004-2005 Albert Beevendorp. All rights reserved.
// ; Copyright (c) 2005 Jussi Pitkänen. All rights reserved.
// ;
// ; Redistribution and use in source and binary forms, with or without
// ; modification, are permitted provided that the following conditions
// ; are met:
// ; 1. Redistributions of source code must retain the above copyright
// ; notice, this list of conditions and the following disclaimer.
// ; 2. Redistributions in binary form must reproduce the above copyright
// ; notice, this list of conditions and the following disclaimer in the
// ; documentation and/or other materials provided with the distribution.
// ;
// ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ;
// ;-------------------
// ; help function area
// ;-------------------
// ; Note: Functions defined in "main.asm" are disabled here.
// ; F380-F384: interslot read
// ;RDPRIM: equ $F380
// ; F385-F38B: interslot read
// ;WRPRIM: equ $F385
// ; F38C-F399: interslot call
// ;CLPRIM: equ $F38C
// ; F39A-F3AD: workarea for the DEF USR statement
// ; this area is initialized with the 10 times the value $475A, which gives
// ; the error 'Syntax Error'
const USRTAB = 0xf39a
// ;----------------------
// ; screen parameter area
// ;----------------------
// ; F3AE: # of positions on a line in SCREEN 0 (ini:39)
const LINL40 = 0xf3ae
// ; F3AF: # of positions on a line in SCREEN 1 (ini:29)
const LINL32 = 0xf3af
// ; F3B0: # of actually used positions in the current screenmodus (ini:39)
const LINLEN = 0xf3b0
// ; F3B1: # of used lines on screen (ini:24)
const CRTCNT = 0xf3b1
// ; F3B2: # of positions within a tabulator-column (ini:14)
const CLMLST = 0xf3b2
// ; F3B3-F3B4: BASE(0): name table address for SCREEN 0 (ini:$0000)
// ; used to initialize NAMBAS when SCREEN 0 is activated
const TXTNAM = 0xf3b3
// ; F3B5-F3B6: BASE(1): color table address for SCREEN 0, unused? (ini:$0000)
const TXTCOL = 0xf3b5
// ; F3B7-F3B8: BASE(2): pattern table address for SCREEN 0 (ini:$0800)
// ; used to initialize CGPBAS when SCREEN 0 is activated
const TXTCGP = 0xf3b7
// ; F3B9-F3BA: BASE(3): sprite attribute table address for SCREEN 0, unused (ini:$0000)
// ; used to initialize ATRBAS when SCREEN 0 is activated
const TXTATR = 0xf3b9
// ; F3BB-F3BC: BASE(4): sprite pattern table address for SCREEN 0, unused (ini:$0000)
// ; used to initialize PATBAS when SCREEN 0 is activated
const TXTPAT = 0xf3bb
// ; F3BD-F3BE: BASE(5): nametable address for SCREEN 1 (ini:$1800)
// ; used to initialize NAMBAS when SCREEN 1 is activated
const T32NAM = 0xf3bd
// ; F3BF-F3C0: BASE(6): color table address for SCREEN 1 (ini:$2000)
const T32COL = 0xf3bf
// ; F3C1-F3C2: BASE(7): pattern table address for SCREEN 1 (ini:$0000)
// ; used to initialize CGPBAS when SCREEN 1 is activated
const T32CGP = 0xf3c1
// ; F3C3-F3C4: BASE(8): sprite attribute table address for SCREEN 1 (ini:$1B00)
// ; used to initialize ATRBAS when SCREEN 1 is activated
const T32ATR = 0xf3c3
// ; F3C5-F3C6: BASE(9): sprite pattern table address for SCREEN 1 (ini:$0800)
// ; used to initialize PATBAS when SCREEN 1 is activated
const T32PAT = 0xf3c5
// ; F3C7-F3C8: BASE(10): name table address for SCREEN 2 (ini:$1800)
// ; used to initialize NAMBAS when SCREEN 2 is activated
const GRPNAM = 0xf3c7
// ; F3C9-F3CA: BASE(11): color table address for SCREEN 2 (ini:$2000)
const GRPCOL = 0xf3c9 // ; Screen2 Color
// ; F3CB-F3CC: BASE(12): pattern table address for SCREEN 2 (ini:$0000)
// ; used to initialize CGPBAS when SCREEN 2 is activated
const GRPCGP = 0xf3cb
// ; F3CD-F3CE: BASE(13): sprite attribute table address for SCREEN 2 (ini:$1B00)
// ; used to initialize ATRBAS when SCREEN 2 is activated
const GRPATR = 0xf3cd
// ; F3CF-F3D0: BASE(14): sprite pattern table address for SCREEN 2 (ini:$3800)
// ; used to initialize PATBAS when SCREEN 2 is activated
const GRPPAT = 0xf3cf
// ; F3D1-F3D2: BASE(15): name table address for SCREEN 3 (ini:$0800)
// ; used to initialize NAMBAS when SCREEN 3 is activated
const MLTNAM = 0xf3d1
// ; F3D3-F3D4: BASE(16): color table address for SCREEN 3 (ini:$0000)
// ; the color table is unused in SCREEN 3
const MLTCOL = 0xf3d3
// ; F3D5-F3D6: BASE(17): pattern table address for SCREEN 3 (ini:$0000)
// ; used to initialize CGPBAS when SCREEN 3 is activated
const MLTCGP = 0xf3d5
// ; F3D7-F3D8: BASE(18): sprite attribute table address for SCREEN 3 (ini:$1B00)
// ; used to initialize ATRBAS when SCREEN 3 is activated
const MLTATR = 0xf3d7
// ; F3D9-F3DA: BASE(19): sprite pattern table address for SCREEN 3 (ini:$3800)
// ; used to initialize PATBAS when SCREEN 3 is activated
const MLTPAT = 0xf3d9
// ; F3DB: keyclick when a key is pressed: 0: no, 1: yes (ini: 1)
// ; SCREEN ,,n will write to this address
const CLIKSW = 0xf3db
// ; F3DC: line where the cursor is located
// ; starts to count at 1 for the topmost line
const CSRY = 0xf3dc
// ; F3DD: column where the cursor is located
// ; starts to count at 1 for the leftmost column
const CSRX = 0xf3dd
// ; F3DE: function key definition shown: 0: no, -1: yes
// ; Note: MSX BIOS will mess up end-of-screen if this variable contains
// ; something other than $00 or $FF.
const CNSDFG = 0xf3de
// ; F3DF-D3E6: storage for the last written value towards VDP registers 0 till 7
// ; this is needed because these registers are write only
const RG0SAV = 0xf3df
const RG1SAV = 0xf3e0
const RG2SAV = 0xf3e1
const RG3SAV = 0xf3e2
const RG4SAV = 0xf3e3
const RG5SAV = 0xf3e4
const RG6SAV = 0xf3e5
const RG7SAV = 0xf3e6
// ; F3E7: last read value of VDP register 8
const STATFL = 0xf3e7
// ; F3E8: information about the joystick and space bar
// ; 7 6 5 4 3 2 1 0
// ; | | | | +-- Space bar, trig(0) (0 = pressed)
// ; | | | +---------- Stick 1, Trigger 1 (0 = pressed)
// ; | | +------------ Stick 1, Trigger 2 (0 = pressed)
// ; | +-------------- Stick 2, Trigger 1 (0 = pressed)
// ; +---------------- Stick 2, Trigger 2 (0 = pressed)
const TRGFLG = 0xf3e8
// ; F3E9: code for the standard foreground color (ini:15)
const FORCLR = 0xf3e9
// ; F3EA: code for the standard background color (ini:4)
const BAKCLR = 0xf3ea
// ; F3EB: code for the standard border color (ini:7)
const BDRCLR = 0xf3eb
// ; F3EC-F3EE: Jump instruction used by Basic LINE command.
// ; The routines used are: RIGHTC, LEFTC, UPC and DOWNC
const MAXUPD = 0xf3ec
// ; F3EF-F3F1: Jump instruction used by Basic LINE command.
// ; The routines used are: RIGHTC, LEFTC, UPC and DOWNC
const MINUPD = 0xf3ef
// ; F3F2: working color, as used for graphical operations
// ; normally equals to the foreground color (ini:15)
const ATRBYT = 0xf3f2
// ; F3F3-F3F4: starting value of the address of the queue-table
// ; the queue-table contains 4 queue's: 3 for sound and one for RS232
// ; (ini: QUETAB ($F959))
const QUEUES = 0xf3f3
// ; F3F5: CLOAD flag =0 when CLOAD =255 when CLOAD?
const FRCNEW = 0xf3f5
// ; F3F6: VDP-interupt counter that counts from 3 to 0, when it reaches zero, the
// ; keyboard matrix is scanned, and the counters is reset at 3
const SCNCNT = 0xf3f6
// ; F3F7: key repeat counter. Runs from 13 to 0, and is changed when SCNCNT is changed
// ; if the key remained the same. If it reaches 0, keyrepetition starts. If another key
// ; is pressed the value is reset at 13.
const REPCNT = 0xf3f7
// ; F3F8-F3F9: first free space in the inputbuffer of the keyboard
// ; everytime a key is added to the inputbuffer, this address is incremented,
// ; when it equals to GETPNT, the buffer is full
// ; the buffer is located at KEYBUF
const PUTPNT = 0xf3f8
// ; F3FA-F3FB: address in inputbuffer of first character that is not yet read
// ; everytime a key is read from the buffer it is incremented
// ; the buffer is located at KEYBUF
const GETPNT = 0xf3fa
// ; F3FC-F400: memory area for tape system parameters for 1200 baud
// ; F3FC: length of low signal for 0 (ini:83)
// ; F3FD: length of high signal for 0 (ini:92)
// ; F3FE: length of low signal for 1 (ini:38)
// ; F3FF: length of high signal for 1 (ini:45)
// ; F400: length of synchronization block (ini:15)
const CS120 = 0xf3fc
// ; F401-F405: memory area for tape system parameters for 1200 baud
// ; F401: length of low signal for 0 (ini:37)
// ; F402: length of high signal for 0 (ini:45)
// ; F403: length of low signal for 1 (ini:14)
// ; F404: length of high signal for 1 (ini:22)
// ; F405: length of synchronization block (ini:31)
const CS240 = 0xf401
// ; F406-F407: lenghts of signal for 0 for the current speed of the tape system
// ; either equal to the content of F3FC-F3FD or the content of F401-F402
// ; (ini: 83, 92)
const LOW_ = 0xf406 // ; real name: LOW, but doesn't compile?
// ; F408-F409: lenghts of signal for 1 for the current speed of the tape system
// ; either equal to the content of F3FE-F3FF or the content of F403-F404
// ; (ini: 38, 45)
const HIGH_ = 0xf408 // ; real name: HIGH, but doesn't compile?
// ; F40A: lenghts of synchronization block for the current speed of the tape system
// ; either equal to the content of F400 or the content of F405 (ini: 15)
const HEADER = 0xf40a
// ; F40B-F40C: standard setting for the height/width aspect of the
// ; BASIC statement CIRCLE; only the byte in F40B is actually used
// ; If ASPECT2 is larger then 255, the value of F40B is the number of horizontal
// ; dots per 256 verical dots of the radius (ini:$0100)
// ; ! not verified :)
const ASPCT1 = 0xf40b
// ; F40D-F40E: standard setting for the height/width aspect of the
// ; BASIC statement CIRCLE; If ASPCT2 is smaller then 512, then ASPCT2 is the
// ; number of vertical dots per 256 horizontal dots of the radius (ini:$0100)
// ; ! not verified :)
const ASPCT2 = 0xf40d
// ; F40F-F413: work area for the BASIC statement RESUME NEXT
// ; contains a fake end of basic program
// ; (ini: 58, 0, 0, 0, 0)
const ENDPRG = 0xf40f
// ; F414: errornumber of last error that happened while executing a BASIC program
// ; (ini:0)
const ERRFLG = 0xf414
// ; F415: number of characters in the writebuffer of the printer that still
// ; need printing
const LPTPOS = 0xf415
// ; F416: switch indicating if output should be screen or printer
// ; (think LIST vs LLIST) (ini:0) values: 0: screen, 1: printer
const PRTFLG = 0xf416
// ; F417: switch indicating if hooked up printer is an MSX printer or not
// ; values: 0: MSX-Printer, 1: no MSX-Printer
// ; if the printer is no MSX-Printer, non-ASCII (>=128) characters are replaced
// ; by spaces before sending them to the printer (ini: 0)
const NTMSXP = 0xf417
// ; F418: switch indicating of printing routines should use raw-mode or
// ; should convert:
// ; =0 to convert tabs and unknown characters to spaces and remove graphical headers
// ; =1 to send data just like it gets it (ini: 0)
// ; if RAWPRT is 1, the value if NTMSXP is ignored
const RAWPRT = 0xf418
// ; ---------------------------
// ; basic interpreter work area
// ; ---------------------------
// ; F419-F41A: work area for the BASIC command VAL: contains address of character that
// ; has temporarely been replaced by O by VAL
const VLZADR = 0xf419
// ; F41B: work area for the BASIC command VAL: contains the character originally at
// ; the location of VLZADR
const VLZDAT = 0xf41b
// ; F41C-F41D: line number of current BASIC line being executed, in direct modus this
// ; contains $FFFF (ini:$FFFF)
const CURLIN = 0xf41c
// ; F41E: error detection prefix for KBUF, always contains ":"
// ; originally undocumented :)
const KBFMIN = 0xf41e
// ; F41F-F55C: workarea for coding basic rules that have been typed in direct modus
// ; this are contains the code for the line interpreted in direct modus
const KBUF = 0xf41f
// ; F55D: byte used as first byte of BUF for input statements, giving them always
// ; an extra ',' (ini:44 == ',')
const BUFMIN = 0xf55d
// ; F55E-F65F: used in direct modus to store the ASCII codes of the line, or simulary
// ; for INPUT or LINE INPUT BASIC statements
const BUF = 0xf55e
// ; F562-F570: used by bitblit routines to store the register data
const SX = 0xf562
const SY = 0xf564
const DX = 0xf566
const DY = 0xf568
const NX = 0xf56a
const NY = 0xf56c
const CDUMMY = 0xf56e
const ARG_ = 0xf56f
const L_OP = 0xf570
// ; F660: last usable byte of BUF
const ENDBUF = 0xf660
// ; F661: number of column of last written character on the screen
const TTYPOS = 0xf661
// ; F662: switch indicating during variable lookup for arrays, if this has not already
// ; been done for a DIM BASIC statement
const DIMFLG = 0xf662
// ; F663: workarea for evaluation of expressions; contains type of last evaluated
// ; expression; the value of the expression is in DAC, possible values of VALTYP:
// ; 2: integer
// ; 3: string
// ; 4: normal real
// ; 8: double real
const VALTYP = 0xf663
// ; F664: workarea for coding of BASIC statements. switch indicating if keywords have
// ; to be encoded or not. E.g. in DATA fields they should not be encoded
// ; 0: encoding on, 1: encoding off
const DORES = 0xf664
// ; F665: workarea for coding of BASIC statements. swithc indication of numbers have to be
// ; encoded; values: $0: encode as const, $1: encode as line number, $FF: do not encode
const DONUM = 0xf665
// ; F666-F667: work area for evaluation of expressions: contains address of first character
// ; after the code of the last evaluated expression
const CONTXT = 0xf666
// ; F668: work area for evaluation of expressions: contains information byte about the
// ; encoding of the last evaluated constant number; value of this constant is in CONLO
// ; values:
// ; $0B: octal (2 bytes)
// ; $0C: hexadecimal (2 bytes)
// ; $0F: decimal 0<=value<256 (1 byte)
// ; $11-$1B: short encoding for 0->10
// ; $1C: decimal (2bytes, 2s-compliment)
// ; $26: $42 binary as ASCII
// ; $0E: line number
// ; $0D: line pointer
// ; $1D: normal real (1 byte exp, 3 bytes BCD)
// ; $1F: double real (1 byte exp, 7 bytes BCD)
const CONSAV = 0xf668
// ; F669: work area for evaluation of expressions: contains type of last evaluated number
// ; constant; the value is in CONLO, for values of CONTYP, see VALTYP
// ; Strings are never contant in BASIC!
const CONTYP = 0xf669
// ; F66A-F671: work area for evaluation of expressions: contains the value of the last
// ; evaluated number contant; value starts at F66A, and takes bytes as needed for the type
const CONLO = 0xf66a
// ; F672-F673: upper limit of memory area reserved for strings, contains the upper address
// ; that is allowed to be used
const MEMSIZ = 0xf672
// ; F674-F675: top of stack; also first byte below string area
const STKTOP = 0xf674
// ; F676-F677: start address of current basic program, set at initialization, and
// ; not changed by OS (ini:$8001)
const TXTTAB = 0xf676
// ; F678-F679: address of first unused string-descriptor in TEMPST
// ; (ini:value of TEMPST)
const TEMPPT = 0xf678
// ; F67A-F697: work area for evaluation of string expressions; this area has space
// ; for 10 string descriptors of 3 bytes; these can be used for temporarely results
// ; of string arythmetics
const TEMPST = 0xf67a
// ; F698-F69A: work area for evaluation of string expressions; this contains the
// ; string descriptor of the intermediate result
const DSCTMP = 0xf698
// ; F69B-F69C: first address within the string memory area that is still free
// ; the string area is filled backwards, soo the lower the value, the less space
// ; remains (ini: value of MEMSIZ)
const FRETOP = 0xf69b
// ; F69D-F69E: temporarely storage for adminstration of the basic interpreter
const TEMP3 = 0xf69d
// ; F69F-F6A0: temporarely storage for garbage collection
const TEMP8 = 0xf69f
// ; F6A1-F6A2: address of first byte in BASIC-code after last FOR statement
const ENDFOR = 0xf6a1
// ; F6A3-F6A4: line number of last used line of DATA statements
const DATLIN = 0xf6a3
// ; F6A5: switch indicating if a variable is allowed to be an array variable.
// ; This is e.g. not allowed for the loop variable of a FOR statement
// ; 0 = allowed, 1 = not allowed
const SUBFLG = 0xf6a5
// ; F6A6: switch indicating if currently a READ or INPUT statement is being executed
const FLKINP = 0xf6a6
// ; F6A7-F6A8: temporarely storage for adminstration of the basic interpreter
const TEMP = 0xf6a7
// ; F6A9: switch indicating if there are still linenumber constants in the BASIC code
// ; that are encoded as pointers?
const PTRFLG = 0xf6a9
// ; F6AA: switch indication if currently an AUTO statement is active
// ; 0 = no auto, 1 = auto
const AUTFLG = 0xf6aa
// ; F6AB-F6AC: last generated AUTO line number
const AUTLIN = 0xf6ab
// ; F6AD-F6AE: last used AUTO increment
const AUTINC = 0xf6ad
// ; F6AF-F6B0: work area of the error system; contains address of first byte
// ; of statement currently being executed
const SAVTXT = 0xf6af
// ; F6B1-F6B2: work area of the error system; contains address of the stack
// ; before executing of the current statement started
const SAVSTK = 0xf6b1
// ; F6B3-F6B4: line number of last failed line
const ERRLIN = 0xf6b3
// ; F6B5-F6B6: line number of last used (changed, listed, added) line
const DOT = 0xf6b5
// ; F6B7-F5B8: work area of the error system; contains the address of the first
// ; byte of the statement that last failed; on failure it is stored with the
// ; content of SAVTXT
const ERRTXT = 0xf6b7
// ; F6B9-F6BA: work area of the error system; contains the line number where
// ; execution should go to on error (as in basic: ON ERROR GOTO x)
const ONELIN = 0xf6b9
// ; F6BB-F6BC: work area of the error system; indication if the interpreter is
// ; currently executing an error catch routine
// ; 0 = no, FF = yes
const ONEFLG = 0xf6bb
// ; F6BC-F6BD: temporarely storage for the interpreter
const TEMP2 = 0xf6bc
// ; F6BE-F6BF: line number of last program break, reset at 0 at any program change
const OLDLIN = 0xf6be
// ; F6C0-F6C1: address of first statement that is not executed due to a break
const OLDTXT = 0xf6c0
// ; F6C2-F6C3: begin address of storage of basic variables and function descriptors;
// ; possibly adjusted when program changes in size
const VARTAB = 0xf6c2
// ; F6C4-F6C5: begin address of array variables; possibly adjusted when program
// ; changes size or more variables are allocated
const ARYTAB = 0xf6c4
// ; F6C6-F6C7: address of first free byte not used for storage of code or variables
// ; (ini: $8003)
const STREND = 0xf6c6
// ; F6C8-F6C9: address where data needs to be searched at next READ statement
const DATPTR = 0xf6c8
// ; F6CA-F6E3: table with variable types, one for each letter in the alphabet
// ; possible values:
// ; 2 = integer 3 = string 4 = single 8 = double
const DEFTBL = 0xf6ca
// ; F6E4-F7B4: work area for execution of self defined functions
// ; F6E4-F6E5: contains address ; of previous parameter block on the stack;
// ; needed for garbage collection
const PRMSTK = 0xf6e4
// ; F6E6-F6E7: amount of valid bytes in PARM1
const PRMLEN = 0xf6e6
// ; F6E8-F74B: contains definitions of the variables in the parameter lists
// ; of self defined functions
const PARM1 = 0xf6e8
// ; F74C-F74D: previous value of PRMSTK
const PRMDRV = 0xf74c
// ; F74E-F74F: number of valid bytes in PARM2
const PRMLN2 = 0xf74e
// ; F750-F7B3: area used for calculation of values that end up in PARM1
const PARM2 = 0xf750
// ; F7B4: switch indicating of while searching a variable name PARM1 has
// ; been looked at; 0 = no, 1 = yes
const PRMFLG = 0xf7b4
// ; F7B5-F7B6: address of first byte where it is no longer needed to search
// ; for a variable name; it is equal to ARYTAB when the normal variable area
// ; is searched, and equal to PARM1+PRMLEN when PARM1 is searched
const ARYTA2 = 0xf7b5
// ; F7B7-F7B8: switch indicating iif PARM1 contains a valid parameter block
// ; 0 = no, 1 = yes
const NOFUNS = 0xf7b7
// ; F7B8-F7B9: temporarely memory used while searching parameter blocks on
// ; the stack
const TEMP9 = 0xf7b8
// ; F7BA-F7BB: counter of the nesting-dept of the function being evaluated
const FUNACT = 0xf7ba
// ; F7BC-F7C3: work area when executing the SWAP statement; the first variable
// ; is stored here
const SWPTMP = 0xf7bc
// ; F7C4: switch indicating if TRON is on; 0 = off, >0 = on
const TRCFLG = 0xf7c4
// ; F7C5-F7F4: workarea when executing numeric operators
const FBUFFR = 0xf7c5
const DECTMP = 0xf7f0
const DECTM2 = 0xf7f2
const DECCNT = 0xf7f4
// ; F7F6-F805: workarea when executing numeric operators; intermediate
// ; results are stored here; also used for parameter transfer when using
// ; the USR functions; VALTYPE then contains the type, and the value is
// ; stored like this:
// ; typename type where
// ; integer 2 F7F8-F7F9
// ; string 3 F7F8-F7F9 (address descriptor)
// ; single 4 F7F6-F7F9
// ; double 8 F7F6-F7FD
const DAC = 0xf7f6
// ; F806-F856: workarea when executing numeric operators
const HOLD8 = 0xf806
const HOLD2 = 0xf836
const HOLD = 0xf83e
const ARG = 0xf847
// ; F857-F85E: last calculated random double
const RNDX = 0xf857
// ; --------------------
// ; filesystem work area
// ; --------------------
// ; F85F: # of filedescriptors reserved minus 1
// ; this is also the maximum number of open files possible
const MAXFIL = 0xf85f
// ; F860-F861: start address of the file information table
const FILTAB = 0xf860
// ; F862-F863: start address of the first file-buffer
const NULBUF = 0xf862
// ; F864-F865: during file I/O the start address of the active file-buffer
const PTRFIL = 0xf864
// ; F866: flag indicating if the file that is being loaded have to be started
// ; immediately; 0 = no, FF = yes
const RUNFLG = 0xf866
// ; note that RUNFLG and FILNAM overlap!
// ; F866-F870: filename of last file that has been active;
// ; first 8 chars are name, last 3 are extension
const FILNAM = 0xf866
// ; F871-F87B: second filename if needed, e.g. the NAME command
const FILNM2 = 0xf871
// ; F87C: switch indicating if currently a BASIC program is being loaded
// ; 0 = no, 1 = yes
const NLONLY = 0xf87c
// ; F87D-F87E: workarea for BLOAD and BSAVE; when a part of normal memory
// ; is written, it contains the end address of the written memory region
// ; if video memory is written it contains $4BE5 + start address of the
// ; written memory region ??
const SAVEND = 0xf87d
// ; F87F-F91E: storage area for the text of the function keys 10x16 bytes,
// ; but strings need to be zero-terminated, soo maximum length of command is
// ; 15 characters
const FNKSTR = 0xf87f
// ; ------------------------
// ; screen routine work area
// ; ------------------------
// ; F91F-F921: start address of the standard ASCII pattern table
// ; at every change towards a text mode it is copied in the pattern table
// ; of the VDP
// ; F91F: slot indication (ini: 0)
// ; F920-F921: address (ini: 1BBF)
// ; TODO: make CBIOS use this value instead of hardcoded value
const CGPNT = 0xf91f
// ; F922-F923: start address of the nametable in the VRAM
const NAMBAS = 0xf922
// ; F924-F925: start address of the pattern table in the VRAM
const CGPBAS = 0xf924
// ; F926-F927: start address of the sprite pattern table in the VRAM
const PATBAS = 0xf926
// ; F928-F929: start address of the sprite location table in the VRAM
const ATRBAS = 0xf928
// ; F92A-F92B: address in VRAM of the pattern of the current position
// ; on screen
const CLOC = 0xf92a
// ; F92C: mask for CLOC selecting the right bits that correspond with
// ; the current position
const CMASK = 0xf92c
// ; F92D-F930: work area for graphical calculations
const MINDEL = 0xf92d
const MAXDEL = 0xf92f
// ; ----------------------------------------------
// ; F931-F941: work area for calculation of CIRCLE
// ; ----------------------------------------------
// ; F931-F932: ratio of # of dots in the horizontal and vertical direction
// ; if = $0100 then ASPCT1 and ASPCT2 are used
// ; if < $0100 then it is the # of dots in one direction for each
// ; $0100 # of dots in the other direction; the direction is indicated
// ; by CSCLXY
const ASPECT = 0xf931
// ; F933:F934: ; distance, in # of dots from the center of the most
// ; distant point of the circle
const CENCNT = 0xf933
// ; F935: switch indication if the start and/or end point need to be
// ; connected to the center
// ; bit 7: connect end point; 1 = yes
// ; bit 0: connect start point; 1 = yes
const CLINEF = 0xf935
// ; F936-F937: used during calculation of CIRCLE
const CNPNTS = 0xf936
// ; F938: direction of drawing of circle:
// ; 00 = from CSTCNT towards CENCNT
// ; FF = from CENCNT towards CSTCNT
const CPLOTF = 0xf938
// ; F939-F93A: used during calculation of CIRCLE
const CPCNT = 0xf939
// ; F93B-F93C: ; contains the total # of dots of the full circle,
// ; even when only a part is drawn
const CPCNT8 = 0xf93b
// ; F93D-F93E: used during calculation of CIRCLE
const CRCSUM = 0xf93d
// ; F93F-F940: ; distance in dots from the center towards the closest
// ; circle point
const CSTCNT = 0xf93f
// ; F941: switch indicating if the X or Y direction needs to be streched:
// ; 0 = X, 1 = Y
const CSCLXY = 0xf941
// ; F942-F943: store of CLOC, also used for PAINT
const CSAVEA = 0xf942
// ; F944: storage of CMASK; also used for PAINT
const CSAVEM = 0xf944
// ; F945-F946: horizontal distance towards the center
const CXOFF = 0xf945
// ; F947-F948: vertical distance towards the center
const CYOFF = 0xf947
// ; -------------------------------------------
// ; work area for executing the PAINT statement
// ; -------------------------------------------
// ; F949: leftmost position of protrusion towards the left
const LOHMSK = 0xf949
// ; F94A: new workdirection for protrusion towards the left
const LOHDIR = 0xf94a
// ;F94B-F94C: leftmost position of protrusion towards the left
const LOHADR = 0xf94b
// ; F94D: size of protrusion towards the left
const LOHCNT = 0xf94d
// ; F94F-F950: # of pixels that may be skipped
const SKPCNT = 0xf94f
// ; F951-F952: # of movements
const MOVCNT = 0xf951
// ; F953: current direction; $40 = \/, $C0 = /\, $00 = stop
const PDIREC = 0xf953
// ; F954: indicate if paint towards the left worked
const LFPROG = 0xf954
// ; F955: indicate of a paint towards the right worked
const RTPROG = 0xf955
// ; F956-F957: start address of a jumptable for subcommands
// ; contained in a string variable, used for both PLAY and DRAW
// ; where this systemvar points to either the PLAY or the DRAW
// ; table
const MCLTAB = 0xf956
// ; F958: switch indication if MCLTAB is for PLAY or DRAW
// ; $0 = DRAW, $FF = PLAY
const MCLFLG = 0xf958
// ; ------------------------------------------
// ; work area for sound and queueing and RS232
// ; ------------------------------------------
// ; F959-F971: Variables for three music queues and one RS232 queue
// ; F959: VOICAQ put position
// ; F95A: VOICAQ get position
// ; F95B: VOICAQ putback flag
// ; F95C: VOICAQ size
// ; F95D: VOICAQ address
// ; F95F-F964: VOICBQ
// ; F965-F96A: VOICCQ
// ; F96B-F970: RS2IQ
const QUETAB = 0xf959
// ; Putback characters for queues. TODO: what purpose do these have exactly?
const QUEBAK = 0xf971
// ; Buffers for queues.
const VOICAQ = 0xf975 // ; Voice A queue
const VOICBQ = 0xf9f5 // ; Voice B queue
const VOICCQ = 0xfa75 // ; Voice C queue
const RS2IQ = 0xfaf5 // ; RS232 queue
// ; in MSX2 the content of RS2IQ is used differently:
const DPPAGE = 0xfaf5 // ; Display page (SCR5+)
const ACPAGE = 0xfaf6 // ; Active page (SCR5+)
// ; FAF7: AV control port value storage
const AVCSAV = 0xfaf7
// ; FAF8: extended BASIC ROM slot address
const EXBRSA = 0xfaf8
// ; FAF9: character count for ROMA-KANA
const CHRCNT = 0xfaf9
// ; FAFA-FAFB: character save for ROMA-KANA
const ROMA = 0xfafa
// ; ROMA-KANA extension mode switch or VRAM size??
const MODE = 0xfafc
// ;Reserved equ $FAFD
// ; FAFE-FAFF: x position for mouse or lightpen
const XSAVE = 0xfafe
// ; FB00-FB01: y position for mouse or lightpen
const YSAVE = 0xfb00
const LOGOPR = 0xfb02
// ; FB21-FB28: Table which contains info for up to 4 disk ROMs, 2 bytes each:
// ; - first byte: number of drives connected to this interface
// ; - second byte: slot ID of the disk ROM
const DRVINF = 0xfb21
// ; end of MSX2 only usage of RS2IQ
// ; --------------------------------
// ; work area for the PLAY statement
// ; --------------------------------
// ; FB35: status about the parsing of a PLAY string
// ; bit 7: only one time parsed; 1 = yes
// ; bit 1-0: number of parsed strings (0-3)
const PRSCNT = 0xfb35
// ; FB36-FB37: storage of stack
const SAVSP = 0xfb36
// ; FB38: # of voice currently being parsed (0-2)
const VOICEN = 0xfb38
// ; FB39-FB3A: storage of volume of a muted voice
const SAVVOL = 0xfb39
// ; FB3B: size of string being parsed (also used by DRAW)
const MCLLEN = 0xfb3b
// ; FB3C-FB3D: address of string being parsed (also used by DRAW)
const MCLPTR = 0xfb3c
// ; FB3E: temporarely storage of active queue # (0-2)
const QUEUEN = 0xfb3e
// ; FB3F: flag indicating which queues are active
// ; bit 2 = queue 2; 1 = active
// ; bit 1 = queue 1; 1 = active
// ; bit 0 = queue 0; 1 = active
const MUSICF = 0xfb3f
// ; FB40: count of the # of PLAY statements parsed, but not executed yet
const PLYCNT = 0xfb40
// ; FB41-FB65: Voice Control Block for voice A (queue 0)
const VCBA = 0xfb41
// ; FB66-FB8A: Voice Control Block for voice B (queue 1)
const VCBB = 0xfb66
// ; FB8B-FBAF: Voice Control Block for voice C (queue 2)
const VCBC = 0xfb8b
// ; each VCB has the following structure:
// ; name offset length purpose
const METREX = 0 // ; 2 interrupt counter
const VCXLEN = 2 // ; 1 MCLLEN for voice
const VCXPTR = 3 // ; 2 MCLPTR for voice
const VCXSTP = 5 // ; 2 stack pointer
const QLENGX = 7 // ; 1 # bytes in queue
const NTICSX = 8 // ; 2 new counter ?
const TONPRX = 10 // ; 2 pitch
const AMPLTX = 12 // ; 1 amplitude
const ENVPRX = 13 // ; 2 envelope speed
const OCTAVX = 15 // ; 1 octave
const NOTELX = 16 // ; 1 tone length
const TEMPOX = 17 // ; 1 tempo
const VOLUMX = 18 // ; 1 volume
const ENVLPX = 19 // ; 1 envelope shape
const MCLSTX = 33 // ; space for stack storage
const MCLSEX = 36 // ; start of stack
// ; the stack mentioned above is used to store bytevalues
// ; that are readied to be put on the voice queue
// ; -----------------------------------------------
// ; settings for screen editor and interrupt system
// ; -----------------------------------------------
// ; FBB0: switch indicating if software reset is enabled
// ; 0 = n, 1 = yes; can be used to reset BASIC by pressing
// ; SHIFT-CODE-GRAPH; does not erase the existing program
// ; (ini: 0)
const ENSTOP = 0xfbb0
// ; FBB1: switch indicating if the current BASIC program is in a ROM
// ; 0 = no; 1 = yes
const BASROM = 0xfbb1
// ; FBB2-FBC9: table containing for each line if it continues on the
// ; next line; 0 = yes, >0 = no
const LINTTB = 0xfbb2
// ; FBCA-FBCB storage of location of cursor for INLIN and QINLIN
// ; FBCA: CSRY , FBCB: CSRX
const FSTPOS = 0xfbca
// ; ASCII code of the character currently covered by the cursor
// ; TODO: is the name CURSAV or CODSAV ?
const CURSAV = 0xfbcc
// ; FBCD: switch indicating which function keys are to be displayed
// ; on the screen; 0 = F6-F10, 1 = F1-F5
const FNKSWI = 0xfbcd
// ; FBCE-FBD7: for each function key, a flag indicating if it has
// ; interrupt facility enabled; 0 = disabled, 1 = enabled
const FNKFLG = 0xfbce
// ; FBD8: counter of # of interrupts that still have a pending ON .. GOSUB
const ONGSBF = 0xfbd8
// ; FBD9: flag indicating if a keyclick has already been generated, to avoid
// ; keyclicks for a key that generates two ASCII codes
// ; $00 = no click, $0F = click
const CLIKFL = 0xfbd9
// ; FBDA-FBE4: storage of keyboard matrix, used for detection key repetition
const OLDKEY = 0xfbda
// ; FBE5-FBEF: current state of the keyboard matrix
const NEWKEY = 0xfbe5
// ; keyboard buffer; each char entered via the keyboard ends up here
const KEYBUF = 0xfbf0
// ; LIMPNT: something about "key buffer pointer"
const LIMPNT = 0xfc17
// ; FC18-FC3F: work area for processing the last typed line
const LINWRK = 0xfc18
// ; FC40-FC47: storage for the patter of an ASCII character
// ; used when writing an ASCII character in a graphical mode
const PATWRK = 0xfc40
// ; FC48-FC49: lowest address of the RAM memory; initialized at startup
// ; and not changed normally
const BOTTOM = 0xfc48
// ; FC4A-FC4B: highest address of the RAM memory that is not reserved by
// ; the OS; string area, filebuffers and stack are below this address
// ; initialized at startup and not changed normally
const HIMEM = 0xfc4a
// ; FC4C-FC99: table for interrupt facilities of MSX BASIC
// ; each 3 bytes are used like this:
// ; byte 1 is a flag:
// ; bit 2: interrupt happened; 1 = yes
// ; bit 1: interrupt stop; 1 = yes
// ; bit 0: interrupt off; 1 = no
// ; byte 2-3 is the adress of the line in BASIC where should be
// ; jumped too
// ; the offsets in the table are:
// ; offset address interrupt
// ; 0 FC4C F1
// ; 3 FC4F F2
// ; 6 FC52 F3
// ; 9 FC55 F4
// ; 12 FC58 F5
// ; 15 FC5B F6
// ; 18 FC5E F7
// ; 21 FC61 F8
// ; 24 FC64 F9
// ; 27 FC67 F10
// ; 30 FC6A STOP
// ; 33 FC6D sprite collision
// ; 36 FC70 SPACE (trigger 0)
// ; 39 FC73 joystick 1 button 1 (trigger 1)
// ; 39 FC76 joystick 2 button 1 (trigger 2)
// ; 39 FC79 joystick 1 button 2 (trigger 3)
// ; 39 FC7C joystick 2 button 2 (trigger 4)
// ; 39 FC7F interval
const TRPTBL = 0xfc4c
// ; FC9A: usage unknown
const RTYCNT = 0xfc9a
// ; FC9B: STOP indication
// ; 0 = nothing; 3 = CTRL+STOP, 4 = STOP
const INTFLG = 0xfc9b
// ; FC9C: last read Y-position of a touchpad
const PADY = 0xfc9c
// ; FC9D: last read X-position of a touchpad
const PADX = 0xfc9d
// ; FC9E-FC9F: software clock, updated at each VDP interrupt
const JIFFY = 0xfc9e // ; timer counter
// ; FCA0-FCA1: initial value of INTCNT, used when INTCNT
// ; reaches 0; used for ON INTERVAL GOSUB
const INTVAL = 0xfca0
// ; FCA2-FCA3: interrupt counter; lowered at each VDP interrupt;
// ; reset with value of INTVAL when it reaches zero; if interval
// ; interrupt is needed, it is generated
const INTCNT = 0xfca2
// ; FCA4-FCA5: parameter used at tap input, given a value during
// ; reading of a headerblock from tape
const LOWLIM = 0xfca4
const WINWID = 0xfca5
// ; FCA6: flag indicating if the previous character written
// ; to the screen was an extension character for graphical signs
// ; (ASCII 1); 0 = no, 1 = yes
const GRPHED = 0xfca6
// ; FCA7 ESCCNT State of a state machine that handles the printing of escape
// ; sequences. A subset of the VT52 escape sequences is supported.
// ; values:
// ; $00: not inside an escape sequence
// ; $01: seen <ESC>x
// ; $02: seen <ESC>y
// ; $03: seen <ESC>Y<row>
// ; $04: seen <ESC>Y
// ; $FF: seen <ESC>
const ESCCNT = 0xfca7
// ; FCA8: switch indicating insert or overwrite mode
// ; $00 = overwrite; $FF = insert
// ; the value of INSFLG is changed each time the INS key is pressed
const INSFLG = 0xfca8
// ; FCA9: show cursor; 0 = no, 1 = yes
// ; can be changed with escape sequences x5 and y5
const CSRSW = 0xfca9
// ; FCAA: shape of cursor; 0 = block; 1 = insert
// ; pressing the INS key changes the value of CSTYLE
// ; can be changed with escape sequences x4 and y4
const CSTYLE = 0xfcaa
// ; switch indicating if the CAPS-LOCK is on
// ; $00 = off, $FF = on (unofficial: $80 = perma-on)
const CAPST = 0xfcab
// ; FCAC: dead key control in non-japanese MSX models
// ; adds a mark on the next char pressed, if applicable
// ; 0 = no dead key
// ; 1 = dead key => accent grave
// ; 2 = SHIFT + dead key => accent aigu
// ; 3 = CODE + dead key => accent circumflex
// ; 4 = SHIFT + CODE + dead key => trema
// ; in japanese models it controls the charset used
const KANAST = 0xfcac
// ; FCAD: only used in japanese MSX models; it defines
// ; the used typeset (ini: $40)
const KANAMD = 0xfcad
// ; ----
// ; misc
// ; ----
const FLBMEM = 0xfcae
const SCRMOD = 0xfcaf
const OLDSCR = 0xfcb0
const CASPRV = 0xfcb1
const BRDATR = 0xfcb2
const GXPOS = 0xfcb3
const GYPOS = 0xfcb5
const GRPACX = 0xfcb7
const GRPACY = 0xfcb9
const DRWFLG = 0xfcbb
const DRWANG = 0xfcbd
const RUNBNF = 0xfcbe
const SAVENT = 0xfcbf
// ; ---------------------------
// ; storage of slot information
// ; ---------------------------
// ; FCC1-FCC4: Information for each primary slot. The most significant bit is
// ; set if the primary slot is found to be expanded.
const EXPTBL = 0xfcc1
// ; FCC5-FCC8: Duplicate the contents of the four possible secondary slot
// ; registers.
const SLTTBL = 0xfcc5
// ; FCC9-FD08: Information for any extension ROMs found during the power-up
// ; ROM search.
// ; FCC9-FCCC: primary slot 0, secondary slot 0
// ; FCCD-FCD0: primary slot 0, secondary slot 1
// ; FCD1-FCD4: primary slot 0, secondary slot 2
// ; FCD5-FCD8: primary slot 0, secondary slot 3
// ; FCD9-FCE8: primary slot 1
// ; FCE9-FCF8: primary slot 2
// ; FCF9-FD08: primary slot 3
// ; The information is stored as below.
// ; bit 7 (set): BASIC program
// ; bit 6 (set): device handler
// ; bit 5 (set): statement handler
const SLTATR = 0xfcc9
const SLTWRK = 0xfd09
// ; ------------------------------
// ; storage of ROM-page parameters
// ; ------------------------------
const PROCNM = 0xfd89
const DEVICE = 0xfd99
// ; ------------
// ; system hooks
// ; ------------
// ; system hooks are defined in hooks.asm
// ; ------------------
// ; storage of VDP8-23
// ; ------------------
// ; FFE7-FFF6: storage of VDP 8-23
const RG8SAV = 0xffe7
// ; ----------------------
// ; extra slot information
// ; ----------------------
// ; FFF7: slot address of main-rom
// ;?????: equ $FFF7
// ; ------------------
// ; storage of VDP25-27
// ; ------------------
// ; FFFA-FFFC: storage of VDP 25-27
const RG25SAV = 0xfffa
// ; ---------------------------
// ; subslot switching addresses
// ; ---------------------------
// ; FFFF: subslot switching address
// ; This is not actually a system variable, it is a hardware register:
// ; SSL_REGS (see hardware.asm).
// ; -------
// ; the end
// ; -------
// ; vim:ts=8:expandtab:filetype=z8a:syntax=z8a:
// -- end: systemvars.asm
// -- begin: hooks.asm
// ; C-BIOS hook declarations
// ;
// ; Copyright (c) 2002-2003 BouKiCHi. All rights reserved.
// ; Copyright (c) 2003 Reikan. All rights reserved.
// ; Copyright (c) 2004 Maarten ter Huurne. All rights reserved.
// ; Copyright (c) 2004 Manuel Bilderbeek. All rights reserved.
// ; Copyright (c) 2004-2006 Joost Yervante Damad. All rights reserved.
// ;
// ; Redistribution and use in source and binary forms, with or without
// ; modification, are permitted provided that the following conditions
// ; are met:
// ; 1. Redistributions of source code must retain the above copyright
// ; notice, this list of conditions and the following disclaimer.
// ; 2. Redistributions in binary form must reproduce the above copyright
// ; notice, this list of conditions and the following disclaimer in the
// ; documentation and/or other materials provided with the distribution.
// ;
// ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ;
// ; called at start of interrupt subroutine, before it has been checked if
// ; the interrupt was from VDP; used by e.g. RS232
const H_KEYI = 0xfd9a
// ; called at start of interrupt subroutine, when it is clear that
// ; the interrupt is from the VDP
const H_TIMI = 0xfd9f
// ; called at start of CHPUT(00A2)
const H_CHPU = 0xfda4
// ; called at start of the subroutine drawing the cursor
const H_DSPC = 0xfda9
// ; called at start of the subroutine that removes the cursor
const H_ERAC = 0xfdae
// ; called at start of DSPFNK(00CF)
const H_DSPF = 0xfdb3
// ; called at start of ERAFNK(00CC)
const H_ERAF = 0xfdb8
// ; called at start of TOTEXT(00D2)
const H_TOTE = 0xfdbd
// ; called at start of CHGET(009F)
const H_CHGE = 0xfdc2
// ; called at start of the subroutine that fills the pattern-table
// ; can be used to override the default ASCII patterns
const H_INIP = 0xfdc7
// ; called at part of subroutine that decodes combined keystrokes
// ; like with CTRL/CODE/GRAPH/SHIFT to an ASCII code; can be used
// ; to override the working of the keyboard
const H_KEYC = 0xfdcc
// ; called at start of the subroutine that decodes single keystrokes;
// ; can be used to override the working of the keyboard
const H_KYEA = 0xfdd1
// ; called at start of NMI interrupt subroutine
const H_NMI = 0xfdd6
// ; called at start of PINLIN(00AE)
const H_PINL = 0xfddb
// ; called at start of QINLIN(00B4)
const H_QINL = 0xfde0
// ; called at start of INLIN(00B1)
const H_INLI = 0xfde5
// ; BASIC interpreter hook
const H_ONGO = 0xfdea
// ; implementation hook for DSKO$
const H_DSKO = 0xfdef
// ; implementation hook for SET
const H_SETS = 0xfdf4
// ; implementation hook for NAME
const H_NAME = 0xfdf9
// ; implementation hook for KILL
const H_KILL = 0xfdfe
// ; implementation hook for IPL
const H_IPL = 0xfe03
// ; implementation hook for COPY
const H_COPY = 0xfe08
// ; implementation hook for CMD
const H_CMD = 0xfe0d
// ; implementation hook for DSKF
const H_DSKF = 0xfe12
// ; implementation hook for DSKI$
const H_DSKI = 0xfe17
// ; implementation hook for ATTR$
const H_ATTR = 0xfe1c
// ; implementation hook for LSET
const H_LSET = 0xfe21
// ; implementation hook for RSET
const H_RSET = 0xfe26
// ; implementation hook for FIELD
const H_FIEL = 0xfe2b
// ; implementation hook for MKI$
const H_MKIS = 0xfe30
// ; implementation hook for MKS$
const H_MKSS = 0xfe35
// ; implementation hook for MKD$
const H_MKDS = 0xfe3a
// ; implementation hook for CVI
const H_CVI = 0xfe3f
// ; implementation hook for CVS
const H_CVS = 0xfe44
// ; implementation hook for CVD
const H_CVD = 0xfe49
// ; called when looking up the value of PTRFIL(F864) for DISKBASIC
const H_GETP = 0xfe4e
// ; called when PTRFIL(F864) is being given a new value
const H_SETF = 0xfe53
// ; called when an OPEN statement was issued without a FOR-part
// ; part of DISKBASIC
const H_NOFO = 0xfe58
// ; called for an operation for file-buffer 0, in DISKBASIC
const H_NULO = 0xfe5d
// ; called from DISKBASIC for a call with file-buffer not 0
const H_NTFL = 0xfe62
// ; called when doing a MERGE command for disks
const H_MERG = 0xfe67
// ; called when doing a SAVE commands for disks
const H_SAVE = 0xfe6c
// ; called when doing a BSAVE command for disks
const H_BINS = 0xfe71
// ; called when doing a BLOAD command for disks
const H_BINL = 0xfe76
// ; implementation hook for FILES
const H_FILE = 0xfe7b
// ; DISKBASIC hook
const H_DGET = 0xfe80
// ; DISKBASIC hook
const H_FILO = 0xfe85
// ; DISKBASIC hook
const H_INDS = 0xfe8a
// ; DISKBASIC entry for selecting the previous disk station for disk IO
const H_RSLF = 0xfe8f
// ; DISKBASIC entry for remembering the current disk station
const H_SAVD = 0xfe94
// ; implementation hook for LOC
const H_LOC = 0xfe99
// ; implementation hook for LOF
const G_LOF = 0xfe9e
// ; called when doing EOF for a disk in DISKBASIC
const H_EOF = 0xfea3
// ; implementation hook for FPOS
const H_FPOS = 0xfea8
// ; DISKBASIC hook
const H_BAKU = 0xfead
// ; called when BASIC interpreter is decoding the device part of a filename
const H_PARD = 0xfeb2
// ; called when BASIC interpreter finds a file without a device part
const H_NODE = 0xfeb7
// ; DISKBASIC hook
const H_POSD = 0xfebc
// ; called when searching a device by name
const H_DEVN = 0xfec1
// ; BASIC interpreter hook
const H_GEND = 0xfec6
// ; Called when clearing variables during the preparation of a RUN statement.
// ; Also used by the disk ROM to start boot sequence.
const H_RUNC = 0xfecb
// ; called when doing CLEAR
const H_CLEA = 0xfed0
// ; BASIC interpreter hook
const H_LOPD = 0xfed5
// ; BASIC interpreter hook; called at stack error
const H_STKE = 0xfeda
// ; called at the start of ISFLIO(014A)
const H_ISFL = 0xfedf
// ; called at the start of OUTDO(0018)
const H_OUTD = 0xfee4
// ; BASIC interpreter hook
const H_CRDO = 0xfee9
// ; BASIC interpreter hook
const H_DSKC = 0xfeee
// ; called at the end of a BASIC program
const H_PRGE = 0xfef8
// ; BASIC interpreter hook
const H_ERRP = 0xfefd
// ; BASIC interpreter hook
const H_ERRF = 0xff02
// ; BASIC interpreter hook
const H_READ = 0xff07
// ; BASIC interpreter hook
const H_MAIN = 0xff0c
// ; called when executing a BASIC statement in direct mode
const H_DIRD = 0xff11
// ; BASIC interpreter hook
const H_FINI = 0xff16
// ; BASIC interpreter hook
const H_FINE = 0xff1b
// ; called while encoding a just typed BASIC statement
const H_CRUN = 0xff20
// ; called while encoding a just typed BASIC statement
const H_CRUS = 0xff25
// ; called when a keyword has been found while encoding a just typed
// ; BASIC statement
const H_ISRE = 0xff2a
// ; called when a function has been found while encoding a just typed
// ; BASIC statement
const H_NTFN = 0xff2f
// ; called when a non-keyword has been found while encoding a just
// ; typed BASIC statement
const H_NOTR = 0xff34
// ; BASIC interpreter hook
const H_SNGF = 0xff39
// ; BASIC interpreter hook
const H_NEWS = 0xff3e
// ; BASIC interpreter hook
const H_GONE = 0xff43
// ; called at start of CHRGTR(0010)
const H_CHRG = 0xff48
// ; BASIC interpreter hook
const H_RETU = 0xff4d
// ; BASIC interpreter hook
const H_PRTF = 0xff52
// ; BASIC interpreter hook
const H_COMP = 0xff57
// ; BASIC interpreter hook
const H_FINP = 0xff5c
// ; BASIC interpreter hook
const H_TRMN = 0xff61
// ; BASIC interpreter hook
const H_FRME = 0xff66
// ; BASIC interpreter hook
const H_NTPL = 0xff6b
// ; called when calculating the value of an expression in BASIC
const H_EVAL = 0xff70
// ; BASIC interpreter hook
const H_OKNO = 0xff75
// ; BASIC interpreter hook
const H_FING = 0xff7a
// ; called when setting a value to a substring with MID$
const H_ISMI = 0xff7f
// ; called when executing the WIDTH statement
const H_WIDT = 0xff84
// ; called when executing the LIST statement
const H_LIST = 0xff89
// ; BASIC interpreter hook
const H_BUFL = 0xff8e
// ; BASIC interpreter hook
const H_FRQI = 0xff93
// ; BASIC interpreter hook
const H_SCNE = 0xff98
// ; BASIC interpreter hook
const H_FRET = 0xff9d
// ; called when looking up a variable in BASIC
const H_PTRG = 0xffa2
// ; called from within PHYDIO(0144), to allow its implementation
const H_PHYD = 0xffa7
// ; called from within FORMAT(147), to allow its implementation
const H_FORM = 0xffac
// ; called form the error-handling routine of the BASIC interpreter
const H_ERRO = 0xffb1
// ; called at start of LPTOUT(00A5)
const H_LPTO = 0xffb6
// ; called at start of LPTSTT(00A8)
const H_LPTS = 0xffbb
// ; called when executing SCREEN
const H_SCRE = 0xffc0
// ; called when executing PLAY
const H_PLAY = 0xffc5
// ; allows for installation of expansion devices that contain extra OS subroutines
const H_BEXT = 0xffca
// ; vim:ts=8:expandtab:filetype=z8a:syntax=z8a:
// -- end: hooks.asm
// ;-----------------
// ; A memory address for debug
// ;-----------------
const DISPADDR = 0xe010 // ; Memory for dump routine
const LASTSTAC = 0xe000
const SP_REGS = 0xe002
const COMPILE_FONT = YES
// ;---------------------
// ; Jump table
// ;---------------------
// ; $0000 CHKRAM
// org 0x00
DI
JP chkram
// ; Pointer to font
// ; $0004 CGTABL Base address of the MSX character set in ROM
org> 0x0004
data word [B_Font]
org> 0x0006
// ; $0006 VDP.DR Base port address for VDP data read
data vdp_dr = byte [ /*unused*/
VDP_DATA // ; VDP read port
]
// ; $0007 VDP.WR Base port address for VDP data write
data vdp_dw = byte [ /*unused*/
VDP_DATA // ; VDP write port
]
// ; $0008 SYNCHR
org> 0x0008
JP synchr
// ; $000C RDSLT Read memory from an optional slot
org> 0x000c
JP rdslt
// ; $0010 CHRGTR
org> 0x0010
JP chrgtr
// ; $0014 WRSLT Write memory to an optional slot
org> 0x0014
JP wrslt
// ; $0018 OUTDO
org> 0x0018
JP outdo
// ; $001C CALSLT inter slot call routine
org> 0x001c
JP calslt
// ; $0020 DCOMPR Compare HL to DE
org> 0x0020
JP dcompr
// ; $0024 ENASLT Change slot
org> 0x0024
JP enaslt
// ; $0028 GETYPR
org> 0x0028
JP getypr
// ; $002B IDBYT1
org> 0x002b
data idbyt1 = byte [ /*unused*/
// ; Basic ROM version
// ; 7 6 5 4 3 2 1 0
// ; | | | | +-+-+-+-- Character set
// ; | | | | 0 = Japanese, 1 = International (ASCII), 2=Korean
// ; | +-+-+---------- Date format
// ; | 0 = Y-M-D, 1 = M-D-Y, 2 = D-M-Y
// ; +---------------- Default interrupt frequency
// ; 0 = 60Hz, 1 = 50Hz
(LOCALE_CHSET + LOCALE_DATE + LOCALE_INT)
]
// ; $002C IDBYT2
data idbyt2 = byte [ /*unused*/
// ; Basic ROM version
// ; 7 6 5 4 3 2 1 0
// ; | | | | +-+-+-+-- Keyboard type
// ; | | | | 0 = Japanese, 1 = International (QWERTY)
// ; | | | | 2 = French (AZERTY), 3 = UK, 4 = German (DIN)
// ; +-+-+-+---------- Basic version
// ; 0 = Japanese, 1 = International
(LOCALE_KBD + LOCALE_BASIC)
]
// ; $002D Version ID
romid: /*unused*/
org> 0x002d
data byte [
// ; version ID
// ; MSX version number
// ; 0 = MSX 1
// ; 1 = MSX 2
// ; 2 = MSX 2+
// ; 3 = MSX turbo R
MODEL_MSX
]
// ; Bit 0: if 1 then MSX-MIDI is present internally (MSX turbo R only)
data byte [
0
// ; Reserved
0
]
// ; $0030 CALLF Call interslot routine(RST30h version)
org> 0x0030
JP callf
// ; $0038 KEYINT Interrupt routines(RST38,VBlank,Timer...)
org> 0x0038
JP keyint
// ; $003B INITIO Initialize I/O
org> 0x003b
JP initio
// ; $003E INIFNK
org> 0x003e
JP inifnk
// ; $0041 DISSCR Disable screen display
org> 0x0041
JP disscr
// ; $0044 ENASCR Enable screen display
org> 0x0044
JP enascr
// ;---------------
// ;VDP routines
// ;---------------
// ; $0047 WRTVDP
org> 0x0047
JP wrtvdp
// ; $004A RDVRM
org> 0x004a
JP rdvrm
// ; $004D WRTVRM
org> 0x004d
JP wrtvrm
// ; $0050 SETRD
org> 0x0050
JP setrd
// ; $0053 SETWRT Set VRAM Write Address
org> 0x0053
JP setwrt
// ; $0056 FILVRM Fill VRAM
org> 0x0056
JP filvrm
// ; $0059 LDIRMV Copy VRAM to RAM
org> 0x0059
JP ldirmv
// ; $005C LDIRVM Copy RAM to VRAM
org> 0x005c
JP ldirvm
// ; $005F CHGMOD Change VDP screen mode
org> 0x005f
JP chgmod
// ; $0062 CHGCLR
org> 0x0062
JP chgclr
// ; $0066 NMI Non-maskable interrupt
org> 0x0066
JP nmi
// ; $0069 CLRSPR Clear sprites
org> 0x0069
JP clrspr
// ; $006C INITXT Initialize display to mode TEXT1 (SCREEN 0)
org> 0x006c
JP initxt
// ; $006F INIT32 Initialize display to mode GRAPHIC1 (SCREEN 1)
org> 0x006f
JP init32
// ; $0072 INITGRP Initialize display to mode GRAPHIC2 (SCREEN 2)
org> 0x0072
JP inigrp
// ; $0075 INIMLT Initialize display to mode MULTI (SCREEN 3)
org> 0x0075
JP inimlt
// ; $0078 SETTXT
org> 0x0078
JP settxt
// ; $007B SETT32
org> 0x007b
JP sett32
// ; $007E SETGRP
org> 0x007e
JP setgrp
// ; $0081 SETMLT
org> 0x0081
JP setmlt
// ; $0084 CALPAT
org> 0x0084
JP calpat
// ; $0087 CALATR
org> 0x0087
JP calatr
// ; $008A GSPSIZ
org> 0x008a
JP gspsiz
// ; $008D GRPPRT
org> 0x008d
JP grpprt
// ; $0090 GICINI initialize sound IC
org> 0x0090
JP gicini
// ; $0093 WRTPSG
org> 0x0093
JP wrtpsg
// ; $0096 RDPSG
org> 0x0096
JP rdpsg
// ; $0099 STRTMS
org> 0x0099
JP strtms
// ; $009C CHSNS .. check key buffer
org> 0x009c
JP chsns
// ; $009F CHGET .. Get data from keyboard buffer
org> 0x009f
JP chget
// ; $00A2 CHPUT .. Output charactor to display
org> 0x00a2
JP chput
// ; $00A5 LPTOUT
org> 0x00a5
JP lptout
// ; $00A8 LPTSTT
org> 0x00a8
JP lptstt
// ; $00AB CNVCHR
org> 0x00ab
JP cnvchr
// ; $00AE PINLIN
org> 0x00ae
JP pinlin
// ; $00B1 INLIN
org> 0x00b1
JP inlin
// ; $00B4 QINLIN
org> 0x00b4
JP qinlin
// ; $00B7 BREAKX
org> 0x00b7
JP breakx
// ; $00BA ISCNTC
org> 0x00ba
JP iscntc
// ; $00BD CKCNTC
org> 0x00bd
JP ckcntc
// ; $00C0 BEEP
org> 0x00c0
JP beep
// ; $00C3 CLS
org> 0x00c3
JP cls_z
// ; $00C6 POSIT
org> 0x00c6
JP posit
// ; $00C9 FNKSB
org> 0x00c9
JP fnksb
// ; $00CC ERAFNK
org> 0x00cc
JP erafnk
// ; $00CF DSPFNK
org> 0x00cf
JP dspfnk
// ; $00D2 TOTEXT
org> 0x00d2
JP totext
// ; $00D5 GTSTCK .. Get joystick infomation
org> 0x00d5
JP gtstck
// ; $00D8 GTTRIG .. Get trigger infomation
org> 0x00d8
JP gttrig
// ; $00DB GTPAD
org> 0x00db
JP gtpad
// ; $00DE GTPDL
org> 0x00de
JP gtpdl
// ; $00E1 TAPION
org> 0x00e1
JP tapion
// ; $00E4 TAPIN
org> 0x00e4
JP tapin
// ; $00E7 TAPIOF
org> 0x00e7
JP tapiof
// ; $00EA TAPOON
org> 0x00ea
JP tapoon
// ; $00ED TAPOUT
org> 0x00ed
JP tapout
// ; $00F0 TAPOOF
org> 0x00f0
JP tapoof
// ; $00F3 STMOTR
org> 0x00f3
JP stmotr
// ; $00F6 LFTQ
org> 0x00f6
JP lftq
// ; $00F9 PUTQ
org> 0x00f9
JP putq
// ; $00FC RIGHTC
org> 0x00fc
JP rightc
// ; $00FF LEFTC
org> 0x00ff
JP leftc
// ; $0102 UPC
org> 0x0102
JP upc
// ; $0105 TUPC
org> 0x0105
JP tupc
// ; $0108 DOWNC
org> 0x0108
JP downc
// ; $010B TDOWNC
org> 0x010b
JP tdownc
// ; $010E SCALXY
org> 0x010e
JP scalxy
// ; $0111 MAPXY
org> 0x0111
JP mapxy
// ; $0114 FETCHC
org> 0x0114
JP fetchc
// ; $0117 STOREC
org> 0x0117
JP storec
// ; $011A SETATR
org> 0x011a
JP setatr
// ; $011D READC
org> 0x011d
JP readc
// ; $0120 SETC
org> 0x0120
JP setc
// ; $0123 NSETCX
org> 0x0123
JP nsetcx
// ; $0126 GTASPC
org> 0x0126
JP gtaspc
// ; $0129 PNTINI
org> 0x0129
JP pntini
// ; $012C SCANR
org> 0x012c
JP scanr
// ; $012F SCANL
org> 0x012f
JP scanl
// ; $0132 CHGCAP
org> 0x0132
JP chgcap
// ; $0135 CHGSND
org> 0x0135
JP chgsnd
// ; $0138 RSLREG Read infomation of primary slot
org> 0x0138
JP rslreg
// ; $013B WSLREG Write infomation to primary slot
org> 0x013b
JP wslreg
// ; $013E RDVDP Read VDP status
org> 0x013e
JP rdvdp
// ; $0141 SNSMAT Get key matrix
org> 0x0141
JP snsmat
// ; $0144 PHYDIO
org> 0x0144
JP phydio
// ; $0147 FORMAT
org> 0x0147
JP format
// ; $014A ISFLIO
org> 0x014a
JP isflio
// ; $014D OUTDLP
org> 0x014d
JP outdlp
// ; $0150 GETVCP
org> 0x0150
JP getvcp
// ; $0153 GETVC2
org> 0x0153
JP getvc2
// ; $0156 KILBUF Clear keyboard buffer
org> 0x0156
JP kilbuf
// ; $0159 CALBAS Call BASIC interpreter
org> 0x0159
JP calbas
// ; fake EXTROM call, fixes Nemesis 3 reset bug
org> 0x015f
RET
// ; ---------------------
// ; MSX TurboR BIOS calls
// ; ---------------------
// ; $0180 CHGCPU
// ; $0183 GETCPU
// ; $0186 PCMPLY
// ; $0189 PCMREC
// ; -------------------
org> 0x0200
// -- begin: util.asm
// ; C-BIOS utility routines
// ;
// ; Copyright (c) 2004 Maarten ter Huurne. All rights reserved.
// ;
// ; Redistribution and use in source and binary forms, with or without
// ; modification, are permitted provided that the following conditions
// ; are met:
// ; 1. Redistributions of source code must retain the above copyright
// ; notice, this list of conditions and the following disclaimer.
// ; 2. Redistributions in binary form must reproduce the above copyright
// ; notice, this list of conditions and the following disclaimer in the
// ; documentation and/or other materials provided with the distribution.
// ;
// ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ;
// ;----------------------------------
// ; Generic routine that implements a jump table.
// ; Input: HL = address of jump table
// ; A = index in table
// ; Changes: F, HL, BC (these are changed *before* jumping)
proc jump_table() {
C <- A
B <- 0
HL + BC + BC
JP table_jump
}
// ;----------------------------------
// ; Generic routine that implements a search & jump table
// ; Entries in the table consist of (character, jump address) pairs.
// ; If the entry is not found, the routine will just RETurn.
// ;
// ; Input: HL = address of search table
// ; A = item to search for
// ; B = number of entries in the table
// ; Changes: F, BC, HL
proc search_table() {
A -? [HL]
HL ++
JR Z? table_jump
HL ++ ++
DJNZ search_table
return
}
proc table_jump() {
C <- [HL]
HL ++
H <- [HL]
L <- C
JP [HL]
}
// ; vim:ts=8:expandtab:filetype=z8a:syntax=z8a:
// -- end: util.asm
// ;include "slot.asm"
// -- begin: video.asm
// ; C-BIOS video routines
// ;
// ; Copyright (c) 2002-2005 BouKiCHi. All rights reserved.
// ; Copyright (c) 2003 Reikan. All rights reserved.
// ; Copyright (c) 2004-2006 Maarten ter Huurne. All rights reserved.
// ; Copyright (c) 2004-2005 Albert Beevendorp. All rights reserved.
// ; Copyright (c) 2004 Manuel Bilderbeek. All rights reserved.
// ; Copyright (c) 2004 Joost Yervante Damad. All rights reserved.
// ; Copyright (c) 2004-2005 Jussi Pitkänen. All rights reserved.
// ;
// ; Redistribution and use in source and binary forms, with or without
// ; modification, are permitted provided that the following conditions
// ; are met:
// ; 1. Redistributions of source code must retain the above copyright
// ; notice, this list of conditions and the following disclaimer.
// ; 2. Redistributions in binary form must reproduce the above copyright
// ; notice, this list of conditions and the following disclaimer in the
// ; documentation and/or other materials provided with the distribution.
// ;
// ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ;
// ;--------------------------------
// ; $0041 DISSCR
// ; Function : inhibits the screen display
// ; Registers: AF, BC
proc disscr() {
@[RG1SAV] & 0xbf -> B
C <- 1
wrtvdp()
return
}
// ;--------------------------------
// ; $0044 ENASCR
// ; Function : displays the screen
// ; Registers: AF, BC
proc enascr() {
@[RG1SAV] | 0x40 -> B
C <- 1
wrtvdp()
return
}
// ;--------------------------------
// ; 0047$ WRTVDP
// ; Function : write data in the VDP-register
// ; Input : B - data to write
// ; C - number of the register
// ; Output : RG0SAV(F3DF)-RG7SAV(F3E6)
// ; Registers: AF, BC
proc wrtvdp() {
DI
C -reset 7 // ; fixes High Way Star
@B -out VDP_ADDR
@C | 0x80 -out VDP_ADDR
EI
HL -push <- RG0SAV
wrtvdp_sav: /*local*/
A <- B
B <- 0
HL + BC
A -> [HL]
wrtvdp_nosav: /*local*/
HL -pop
return
}
// ;--------------------------------
// ; $004A RDVRM
// ; Function : Reads the content of VRAM
// ; Input : HL - address read
// ; Output : A - value which was read
// ; Registers: AF
proc rdvrm() {
setrd()
// ; wait (at least) 29 t-states between VRAM accesses
A | 0 -in VDP_DATA
return
}
// ;--------------------------------
// ; $004D WRTVRM
// ; Function : Writes data in VRAM
// ; Input : HL - address write
// ; A - value write
// ; Registers: AF
proc wrtvrm() {
AF -push
setwrt()
AF -pop
A -out VDP_DATA
return
}
// ;--------------------------------
// ; $0050 SETRD
// ; Function : Enable VDP to read
// ; Input : HL - for VRAM-address
// ; Registers: AF
proc setrd() {
DI
@L -out VDP_ADDR
@H & 0x3f -out VDP_ADDR
EI
return
}
// ;--------------------------------
// ; $0053 SETWRT
// ; Function : Enable VDP to write
// ; Input : HL - Address
// ; Registers: AF
proc setwrt() {
DI
@L -out VDP_ADDR
@H & 0x3f | 0x40 -out VDP_ADDR
EI
return
}
// ;--------------------------------
// ; $0056 FILVRM
// ; Function : fill VRAM with value
// ; Input : A - data byte
// ; BC - length of the area to be written
// ; HL - start address:
// ; * SCREEN 0..4 -> 14-bit address
// ; * SCREEN 5+ -> 17-bit address (uses ACPAGE)
// ; Using 14-bit address for SCREEN4 doesn't really make sense,
// ; but that's what we have to follow to be compatible.
// ; Registers: AF, BC
proc filvrm() {
AF -push
setwrt()
BC --
C ++
A <- B
B <- C
C@A ++
AF -pop
// ; Note: Interrupts should be enabled here.
// ; Penguin Adventure can hang on boot if the interrupt
// ; comes just after our RET, which is certain if the
// ; memory block written is large enough.
filvrm_lp: /*local*/
A -out VDP_DATA
// ; wait (at least) 29 t-states between VRAM accesses
B --
JR NZ? filvrm_lp
C --
JR NZ? filvrm_lp
return
}
// ;--------------------------------
// ; $0059 LDIRMV
// ; Function : Block transfer from VRAM to memory
// ; Input : BC - blocklength
// ; DE - Start address of memory
// ; HL - Start address of VRAM
// ; Registers: AF BC DE
// ; Note : the function doesn't destroy HL
// ; Note : the routine doesn't change IM
proc ldirmv() {
setrd()
HL -push
DE <-> HL
BC --
C ++
A <- B
B <- C
A ++
C <- VDP_DATA
ldirmv_lp: /*local*/
// ; wait (at least) 29 t-states between VRAM accesses
INI
JP NZ? ldirmv_lp
A --
JR NZ? ldirmv_lp
HL -pop
return
}
// ;--------------------------------
// ; $005C LDIRVM
// ; Function : Block transfer from memory to VRAM
// ; Input : BC - blocklength
// ; DE - Start address of VRAM
// ; HL - Start address of memory
// ; Note : the routine doesn't change IM
// ; Registers: All
proc ldirvm() {
DE <-> HL
setwrt()
DE <-> HL
BC --
C ++
A <- B
B <- C
A ++
C <- VDP_DATA
ldirvm_lp: /*local*/
// ; wait (at least) 29 t-states between VRAM accesses
OUTI
JP NZ? ldirvm_lp
A --
JR NZ? ldirvm_lp
// ; Note: Without this, Quinpl shows glitches.
// ; TODO: Investigate why.
DE <-> HL
return
}
// ;----------------------------------
// ; $005F CHGMOD Changes screen mode
// ; Function : Switches to given screenmode
// ; Input : A - screen mode
// ; Registers: All
proc chgmod() {
// ; Guard against non-existing screen mode.
A -? 4
return-if NC?
// ; Redirect to initialisation routine.
HL <- chgmod_tbl
JP jump_table
data chgmod_tbl = word [ /*local*/
initxt // ; SCREEN0
init32 // ; SCREEN1
inigrp // ; SCREEN2
inimlt // ; SCREEN3
]
}
// ; TODO: Now that we rewrite most regs at the end of CHGMOD,
// ; the ini* routines can just update RG?SAV instead of calling wrtvdp.
proc chgmod_finish() {
// ; Generic state resets.
// ; Write new values from system RAM to the VDP.
DI
// ; Write R#0 - R#7.
HL <- RG0SAV
BC <- (8 * 0x0100 + VDP_ADDR)
D <- 0x80
chgmod_finish_lp: /*local*/
OUTI
A <- B
D -out C ++
A | A
JR NZ? chgmod_finish_lp
EI
JP enascr
}
// ;--------------------------------
// ; $0062 CHGCLR
// ; Function : Changes the screencolors
// ; Input : Foregroundcolor in FORCLR
// ; Backgroundcolor in BAKCLR
// ; Bordercolor in BDRCLR
// ; Registers: All
proc chgclr() {
@[SCRMOD] -? 8
JR Z? chgclr_sc8
A --
AF -push
@[FORCLR] <* 4 & 0xf0 -> L
@[BDRCLR] | L -> B
C <- 7
wrtvdp()
AF -pop
return-if NZ?
// ; SCREEN1
@[FORCLR] <* 4 & 0xf0
HL <- BAKCLR
A | [HL]
HL <- [T32COL]
BC <- 0x20
AF -push
setwrt()
cclr_lp: /*local*/
AF -pop
A -out VDP_DATA
AF -push
BC --
@B | C
JR NZ? cclr_lp
AF -pop
return
chgclr_sc8: /*local*/
// ; SCREEN8
@[BDRCLR] -> B
C <- 7
JP wrtvdp
}
// ;--------------------------------
// ; $0069 CLRSPR
// ; Function : Initialises all sprites
// ; Input : SCRMOD
// ; Registers: All
proc clrspr() {
// ; Check screen mode.
@[SCRMOD] | A
return-if Z? // ; no sprites in SCREEN0
// ; Clear sprite attribute table.
CALL clrspr_attr
// ; Clear sprite colour table.
@[SCRMOD] -? 4 // ; sprite mode 1?
JR C? clrspr_col_skip
HL <- [ATRBAS]
H -- -- // ; HL = (ATRBAS) - $200
BC <- (32 * 16)
@[FORCLR] & 0x0f
filvrm()
clrspr_col_skip: /*local*/
// ; Clear sprite pattern generator table.
HL <- [PATBAS]
BC <- (256 * 8)
A ^ A
filvrm()
return
// ;--------------------------------
// ; Clear sprite attribute table.
clrspr_attr: /*local*/
@[SCRMOD] -? 4
JR C? clrspr_attr_spritemode1
// ; Note: This label is called directly by external routines.
clrspr_attr_spritemode2: /*local*/
E <- 217 // ; Y coordinate
JR clrspr_attr_spritemode_start
}
// ; Note: This label is called directly by external routines.
proc clrspr_attr_spritemode1() {
E <- 209 // ; Y coordinate
fallthrough
}
proc clrspr_attr_spritemode_start() {
HL <- [ATRBAS]
setwrt()
@[FORCLR] -> D
BC <- 0x2000 // ; B = 32 = counter, C = pattern index
DI
clrspr_attr_lp: /*local*/
@E -out VDP_DATA // ; Y coordinate
A <- 0
NOP // ; wait (at least) 29 t-states between VRAM accesses
NOP // ; only 2 nops, as ld a,0 is slow
A -out VDP_DATA // ; X coordinate
<- C
NOP // ; wait (at least) 29 t-states between VRAM accesses
NOP
NOP
A -out VDP_DATA // ; pattern number
C ++
gspsiz()
JR NC? clrspr_attr_8
C ++ ++ ++
clrspr_attr_8: /*local*/
@D -out VDP_DATA // ; color
DJNZ clrspr_attr_lp
EI
return
}
// ;--------------------------------
// ; $006C INITXT
// ; Function : Switch to SCREEN 0
// ; Input : TXTNAM, TXTCGP
// ; Output : NAMBAS, CGPBAS, LINLEN, SCRMOD, OLDSCR
// ; Registers: All
proc initxt() {
// ; Disable video output.
disscr()
// ; New screen mode.
@0x00 -> [SCRMOD] -> [OLDSCR]
// ; Line length.
@[LINL40] -> [LINLEN]
// ; Cursor position: top-left.
@1 -> [CSRY] -> [CSRX]
// ; Table base addresses.
HL <- [TXTNAM] // ; name table
-> [NAMBAS]
HL <- [TXTCGP] // ; pattern table
-> [CGPBAS]
HL <- [TXTATR] // ; sprite attribute table (unused)
-> [ATRBAS]
HL <- [TXTPAT] // ; sprite pattern table (unused)
-> [PATBAS]
// ; Update VDP regs and VRAM.
chgclr()
settxt()
init_font()
cls_screen0()
JP chgmod_finish
}
// ;--------------------------------
// ; $006F INIT32
// ; Function : Switches to SCREEN 1 (text screen with 32*24 characters)
// ; Input : T32NAM, T32CGP, T32COL, T32ATR, T32PAT
// ; Output : NAMBAS, CGPBAS, LINLEN, SCRMOD, OLDSCR
// ; Registers: All
proc init32() {
// ; Disable video output.
disscr()
A <- 0x01 // ; SCREEN1
-> [SCRMOD] -> [OLDSCR]
@1 -> [CSRY] -> [CSRX]
chgclr()
HL@[T32NAM] -> [NAMBAS]
HL@[T32CGP] -> [CGPBAS]
HL@[T32PAT] -> [PATBAS]
HL@[T32ATR] -> [ATRBAS]
init_font()
@[LINL32] -> [LINLEN]
sett32()
clrspr_attr_spritemode1()
cls_screen1()
JP chgmod_finish
}
// ;--------------------------------
// ; $0072 INIGRP
// ; Function : Switches to SCREEN 2 (high resolution screen with 256*192 pixels)
// ; Input : GRPNAM, GRPCGP, GRPCOL, GRPATR, GRPPAT
// ; Output : NAMBAS-ATRBAS, SCRMOD
// ; Registers: All
proc inigrp() {
// ; Disable video output.
disscr()
@0x02 -> [SCRMOD]
chgclr()
HL@[GRPNAM] -> [NAMBAS]
setwrt()
B <- 3
A ^ A
DI
inigrp_lp: /*local*/
A -out VDP_DATA ++
JR NZ? inigrp_lp
DJNZ inigrp_lp
EI
HL@[GRPCGP] -> [CGPBAS]
HL@[GRPATR] -> [ATRBAS]
HL@[GRPPAT] -> [PATBAS]
setgrp()
clrspr_attr_spritemode1()
cls_screen2()
JP chgmod_finish
}
// ;------------------------------
// ; $0075 INIMLT
// ; Function : Switches to SCREEN 3 (multi-color screen 64*48 pixels)
// ; Input : MLTNAM, MLTCGP, MLTCOL, MLTATR, MLTPAT
// ; Output : NAMBAS-ATRBAS, SCRMOD
// ; Registers: All
proc inimlt() {
// ; Disable video output.
disscr()
@0x03 -> [SCRMOD]
chgclr()
HL@[MLTNAM] -> [NAMBAS]
setwrt()
A ^ A
C <- 6
DI
inimlt_loop1: /*local*/
AF -push
E <- 4
inimlt_loop2: /*local*/
AF -push
B <- 32
inimlt_loop3: /*local*/
A -out VDP_DATA ++
DJNZ inimlt_loop3
AF -pop
E --
JR NZ? inimlt_loop2
AF -pop
A + 32
C --
JR NZ? inimlt_loop1
EI
HL@[MLTCGP] -> [CGPBAS]
HL@[MLTATR] -> [ATRBAS]
HL@[MLTPAT] -> [PATBAS]
setmlt()
clrspr_attr_spritemode1()
cls_screen3()
JP chgmod_finish
}
// ;------------------------------
// ; $0078 SETTXT
// ; Function : Switches to VDP in SCREEN 0 mode
// ; Input : TXTNAM, TXTCGP
// ; Registers: All
proc settxt() {
@[RG0SAV] & 0xf1 // ; MASK 11110001
-> B
C <- 0
wrtvdp() // ; write VDP R#0
@[RG1SAV] & 0xe7 // ; MASK 11100111
| 0x10 -> B
C ++
wrtvdp() // ; write VDP R#1
// ; Set the VDP base address registers. This works because
// ; TXTNAM, TXTCOL and TXTCGP are in same order as the VDP
// ; base address registers.
DE <- TXTNAM
C <- 2
A ^ A
set_base_address()
DE ++ // ; Skip TXTCOL.
++
C ++
A ^ A
set_base_address()
return
// ; Switches VDP to TEXT2 mode (SCREEN 0, WIDTH 80).
}
// ;------------------------------
// ; $007B SETT32
// ; Function : Switches VDP to SCREEN 1 mode
// ; Input : T32NAM, T32COL, T32CGP, T32ATR, T32PAT
// ; Registers: All
proc sett32() {
@[RG0SAV] & 0xf1 // ; MASK 11110001
-> B
C <- 0
wrtvdp() // ; write VDP R#0
@[RG1SAV] & 0xe7 // ; MASK 11100111
-> B
C ++
wrtvdp() // ; write VDP R#1
// ; Set the base address registers. This works because T32NAM,
// ; T32COL, T32CGP, T32ATR and T32PAT are in same order as the
// ; VDP base address registers.
DE <- T32NAM
C <- 2
A ^ A
set_base_address()
A ^ A
set_base_address()
A ^ A
set_base_address()
A ^ A
set_base_address()
A ^ A
set_base_address()
return
}
// ;------------------------------
// ; $007E SETGRP
// ; Function : Switches VDP to SCREEN 2 mode
// ; Input: GRPNAM, GRPCOL, GRPCGP, GRPATR, GRPPAT
// ; Registers: All
proc setgrp() {
@[RG0SAV] & 0xf1 // ; MASK 11110001
| 0x02 // ; M3 = 1
-> B
C <- 0
wrtvdp() // ; write VDP R#0
@[RG1SAV] & 0xe7 // ; MASK 11100111
-> B
C ++
wrtvdp() // ; write VDP R#1
// ; Set the base address registers. This works because GRPNAM,
// ; GRPCOL, GRPCGP, GRPATR and GRPPAT are in same order as the
// ; VDP base address registers.
DE <- GRPNAM
C <- 2
A ^ A
set_base_address()
A <- 0x7f
set_base_address()
A <- 0x03
set_base_address()
A ^ A
set_base_address()
A ^ A
set_base_address()
return
}
// ;------------------------------
// ; $0081 SETMLT
// ; Function : Switches VDP to SCREEN 3 mode
// ; Input : MLTNAM, MLTCGP, MLTCOL, MLTATR, MLTPAT
// ; Registers: All
proc setmlt() {
@[RG0SAV] & 0xf1 -> B
C <- 0
wrtvdp()
@[RG1SAV] & 0xe7 | 0x08 // ; M2 = 1
-> B
C ++
wrtvdp()
// ; Set the base address registers. This works because MLTNAM,
// ; MLTCOL, MLTCGP, MLTATR and MLTPAT are in same order as the
// ; VDP base address registers.
DE <- MLTNAM
C <- 2
A ^ A
set_base_address()
A ^ A
set_base_address() // ; TODO: Should we ignore MLTCOL?
A ^ A
set_base_address()
A ^ A
set_base_address()
A ^ A
set_base_address()
return
}
// ;------------------------------
// ; Get an address from a base address table, convert it into a register value,
// ; and set the corresponding VDP base address register.
// ; Input: DE = pointer to a base address table
// ; C = VDP base address register
// ; A = OR-mask over the converted address
// ; Output: DE = DE + 2
// ; C = C + 1
// ; Changes: AF, B, HL
proc set_base_address() {
DE -push
AF -push
// ; Get the shift value.
HL <- set_base_address_table
B <- 0
HL + BC
B <- [HL]
// ; Get the address from (HL) to HL.
DE <-> HL
A <- [HL]
HL ++
H <- [HL]
L <- A
// ; Shift it to left in register A. After this A contains the
// ; converted address.
set_base_address_loop: /*local*/
HL + HL
A +$ A
DJNZ set_base_address_loop
B <- A
// ; Set the base address register.
AF -pop
A | B -> B
wrtvdp()
// ; Increase pointer and register number.
DE -pop ++ ++
C ++
return
data set_base_address_table = byte [ /*local*/
0x00 0x00 0x06 0x0a 0x05 0x09 0x05
]
}
// ;------------------------------
// ; $0084 CALPAT
// ; Returns the address of a sprite pattern in the sprite pattern table.
// ; Input: A = pattern number
// ; Output: HL = address
// ; Changes: AF, DE, HL
proc calpat() {
H <- 0
L <- A
HL + HL + HL + HL
gspsiz()
JR NC? calpat_8
HL + HL + HL
calpat_8: /*local*/
DE <- [PATBAS]
HL + DE
return
}
// ;------------------------------
// ; $0087 CALATR
// ; Returns the address of a sprite in the sprite attribute table.
// ; Input: A = sprite number
// ; Output: HL = address
// ; Changes: AF, DE, HL
proc calatr() {
A + A + A
HL <- [ATRBAS]
D <- 0
E <- A
HL + DE
return
}
// ;------------------------------
// ; $008A GSPSIZ
// ; Returns the current sprite-size in bytes.
// ; Output: A = sprite-size in bytes
// ; CF = set when size is 16x16, otherwise reset
// ; Changes: AF
proc gspsiz() {
@[RG1SAV] >* 2
A <- 8
return-if NC?
A <- 32
return
}
// ;------------------------------
// ; $008D GRPPRT
// ; Function: Places a character on graphic screen
// ; Input: A - Character
// ; GRPACX , GRPACY : X, Y coordinate
// ; FORCLR
// ; Input (SCREEN 5 and above) :
// ; LOGOPR for logical operator
// ; NOTE : the function doesn't support without SCREEN 2
// ; and also slower yet.
// ; Register : AF ???
proc grpprt() {
AF -push
// ; Printable character or control character?
A -? 0x20
JR C? grpprt_control
// ; Different implementation depending on screen mode.
@[SCRMOD] -? 2
JR Z? grpprt_sc2
A -? 5
JR NC? grpprt_sc5 // ; SCRMOD >= 5
grpprt_end: /*local*/
AF -pop
return
grpprt_control: /*local*/
// ; Ignore everything except carriage return ($0D).
A -? 0x0d
JR NZ? grpprt_end
AF -pop
// ; Handle carriage return.
HL -push
BC -push
HL <- [GRPACY]
BC <- 0x08
HL + BC -> [GRPACY]
HL@0x00 -> [GRPACX]
BC -pop
HL -pop
return
grpprt_sc5: /*local*/
AF -pop
// ; TODO: should these routines be merged?
return
grpprt_sc2: /*local*/
AF -pop
HL -push
DE -push
BC -push
AF -push
getpat()
DE <- [GRPACY]
BC <- [GRPACX]
mapxy()
@[FORCLR] -> [ATRBYT]
HL <- [CLOC]
BC <- [GRPCGP]
HL + BC
DE <- PATWRK
@[GRPACY] & 0x07
B <- 0x00
C <- A
HL + BC
CALL grpprt_chr_x
BC <- 0xf0
HL + BC
@[GRPACY] -not & 0x07 -> C
CALL grpprt_chr_x
HL <- [GRPACX]
BC <- 0x08
HL + BC -> [GRPACX]
AF -pop
BC -pop
DE -pop
HL -pop
return
grpprt_chr_x: /*local*/
@[GRPACX] & 0x07
AF -push
BC -push
DE -push
HL -push
CALL grpprt_chr // ; half left
@[GRPACX] & 0x07
JR Z? grpprt_skip_hr
@[CMASK] -not -> [CMASK]
HL -pop
BC <- 0x08
HL + BC
DE -pop
BC -pop
AF -pop
CALL grpprt_chr // ; half right
@[CMASK] -not -> [CMASK]
return
grpprt_skip_hr: /*local*/
BC -pop // ; HL = the result of last grpprt_chr
<- 0x08
HL + BC
BC -pop // ; DE = the result of last grpprt_chr
-pop
AF -pop
return
// ; A = Pattern , B = Pattern in VRAM
grpprt_attr: /*local*/
AF -push
HL -push
BC -push
DE -push
D <- A // ; D = Pattern of charactor
E <- B // ; E = Pattern in VRAM
BC <- [GRPCOL]
HL + BC
C <- A
@[ATRBYT] & 0x0f -> B
rdvrm()
AF -push // ; A = an attribute in VRAM
A & 0x0f -? B
JR Z? grpprt_attr_black
AF -pop -push
A >* 4 & 0x0f -? B
JR NZ? grpprt_attr_nomatch
AF -pop
grpprt_attr_end: /*local*/
DE -pop
BC -pop
HL -pop
AF -pop
return
grpprt_attr_black: /*local*/
AF -pop
grpprt_attr_blk_end: /*local*/
DE -pop
BC -pop
HL -pop
AF -pop
A -not
return
grpprt_attr_nomatch: /*local*/
@D | E -? 0xff
JR Z? grpprt_attr_make_black
AF -pop
B <* 4
A & 0x0f | B
wrtvrm()
JR grpprt_attr_end
grpprt_attr_make_black: /*local*/
AF -pop
A & 0xf0 | B
wrtvrm()
JR grpprt_attr_blk_end
// ; A = X MOD 8,C = Y MOD 8, HL = CLOC
grpprt_chr: /*local*/
B <- C
A ++ -> C
@0x07 ^ B ++ -> B
grpprt_lp: /*local*/
BC -push
rdvrm()
B <- A
A <- [DE]
CALL grpprt_attr
grpprt_sft_lp: /*local*/
C --
JR Z? grpprt_sft_ed
A >* 1
JR grpprt_sft_lp
grpprt_sft_ed: /*local*/
C <- A
@[CMASK] & C -> C // ; charactor with mask
A <- B // ; B = pattern in VRAM
| C
wrtvrm()
HL ++
DE ++
BC -pop
DJNZ grpprt_lp
return
}
data grpprt_text = byte [ /*unused*/
"GRPPRT" 0
]
// ;--------------------------------
// ; 0165h CHKNEW
// ; Is the current screen mode a bitmap mode?
// ; Output: Carry flag set if current screen mode is SCREEN 5 or higher.
// ; Changes: AF
proc chknew() { /*unused*/
@[SCRMOD] -? 5
return
}
// ;--------------------------------
// ; 016Bh BIGFIL
// ; Fills VRAM with a fixed value.
// ; Like FILVRM, but supports 128K of VRAM.
// ; Input: HL = VRAM start address
// ; (ACPAGE) = active VRAM page
// ; BC = number of bytes to fill
// ; A = value to fill VRAM with
// ; Changes: AF, BC
proc bigfil() { /*unused*/
AF -push
nsetwr()
BC --
C ++
A <- B
B <- C
C@A ++
AF -pop
DI
bigfil_lp: /*local*/
A -out VDP_DATA
DJNZ bigfil_lp
C --
JR NZ? bigfil_lp
EI
return
}
// ;--------------------------------
// ; 016Eh NSETRD
// ; Set VRAM address and read mode.
// ; Like SETRD, but supports 128K of VRAM.
// ; Input: HL = VRAM address
// ; (ACPAGE) = active VRAM page
// ; Changes: AF
// ; Note: If an odd-numbered 32K page is active and HL >= $8000,
// ; 16-bit wrap around occurs.
proc nsetrd() {
nset_addr()
@H & 0x3f -out VDP_ADDR // ; A13..A8
EI
return
}
// ;--------------------------------
// ; 0171h NSETWR
// ; Set VRAM address and write mode.
// ; Like SETWRT, but supports 128K of VRAM.
// ; Input: HL = VRAM address
// ; (ACPAGE) = active VRAM page
// ; Changes: AF
// ; Note: If an odd-numbered 32K page is active and HL >= $8000,
// ; 16-bit wrap around occurs.
proc nsetwr() {
nset_addr()
@H & 0x3f | 0x40 -out VDP_ADDR // ; A13..A8
EI
return
}
proc nset_addr() {
@[ACPAGE] | A
JR Z? nset_32k
@[SCRMOD] -? 5
JP C? setwrt
A -? 7 <- [ACPAGE]
JR C? nset_32k // ; SCREEN5/6 -> 32K pages
A + A // ; SCREEN7/8 -> 64K pages
nset_32k: /*local*/
HL -push
A & 0x03 // ; A = 0 0 0 0 0 0 P1 P0
>* 1 -> L // ; L = P0 0 0 0 0 0 0 P1
& 0x80 // ; A = P0 0 0 0 0 0 0 0
^ H // ; A = A15 A14 A13 A12 A11 A10 A9 A8
<*$ 1 // ; CF = A15
L <*$ 1 // ; L = 0 0 0 0 0 0 P1 A15
A <*$ 1 // ; CF = A14
<- L <*$ 1 // ; A = 0 0 0 0 0 P1 A15 A14
DI
A -out VDP_ADDR // ; A16..A14
<- 0x8e -out VDP_ADDR // ; R#14
HL -pop
@L -out VDP_ADDR // ; A7..A0
return
}
// ;--------------------------------
// ; 0174h NRDVRM
// ; Read a byte from VRAM.
// ; Leaves the VRAM in read mode at the byte after the one read.
// ; Like RDVRM, but supports 128K of VRAM.
// ; Input: HL = VRAM address
// ; (ACPAGE) = active VRAM page
// ; Output: A = the byte read
proc nrdvrm() { /*unused*/
nsetrd()
A -in VDP_DATA
return
}
// ;--------------------------------
// ; 0177h NWRVRM
// ; Write a byte to VRAM.
// ; Leaves the VRAM in write mode at the byte after the one written.
// ; Like WRTVRM, but supports 128K of VRAM.
// ; Input: HL = VRAM address
// ; (ACPAGE) = active VRAM page
// ; A = the byte to write
proc nwrvrm() { /*unused*/
AF -push
nsetwr()
AF -pop
A -out VDP_DATA
return
}
// ; VDP routines which only exist in sub rom, but are useful for C-BIOS internal
// ; use as well:
// ;-------------------------------------
// ; $0131(sub) VDPSTA
// ; Read VDP status register.
// ; Input: A = number of status register
// ; Output: A = value read
// ; Changes: F
proc vdpsta() { /*unused*/
DI
// ; Select desired status register.
A -out VDP_ADDR <- (0x80 + 15)
-out VDP_ADDR
// ; Read status register.
A -in VDP_STAT
AF -push
// ; Restore status register 0.
A ^ A -out VDP_ADDR
@(0x80 + 15) -out VDP_ADDR
EI
AF -pop
return
}
// ;--------------------
// ;Initializes VDP routine
// ;--------------------
proc init_vdp() {
A -in VDP_STAT // ; reset latch
BC <- 0x00 // ; R#0
wrtvdp()
BC <- 0xe001 // ; R#1
wrtvdp()
BC <- 0x02 // ; R#2
wrtvdp()
BC <- 0x8003 // ; R#3
wrtvdp()
BC <- 0x0104 // ; R#4
wrtvdp()
BC <- 0x0808 // ; R#8
wrtvdp()
@1 -> [CSRY] -> [CSRX]
cls_screen1()
A <- 0x00
HL <- 0x0800
BC <- 0x0800
filvrm()
// ; for screen 1 color table
A <- 0xf5
HL <- 0x2000
BC <- 0x20
filvrm()
// ; PatGenTbl
// ; 76543210 76543210
// ; 00000100 00000000
// ; 04h 00h
BC <- 0xf507 // ; R#7
wrtvdp()
HL <- B_Font
DE <- 0x0800
BC <- 0x0800
ldirvm()
return
// ; TODO: Is it safe to enable this on MSX1 machines?
// ; Or can we autodetect the VDP?
return
}
// ;------------------------------
// ; Initialise font.
// ; Uploads font to VRAM address specified by CGPBAS.
proc init_font() {
HL <- B_Font
DE <- [CGPBAS]
BC <- 0x0800
JP ldirvm
}
// ;--------------------------------
// ; $00C3 CLS
// ; Clears the screen.
// ; Input: BAKCLR,
// ; Z-Flag has to be low if the main ROM version of CLS is called;
// ; in the sub ROM version of CVS the Z-Flag is ignored.
// ; Changes: AF, BC, DE
// ;TODO: add optional borders to text based screens
// ; -> Should that happen in CLS?
proc cls_z() {
return-if NZ?
fallthrough
}
proc cls() {
@[SCRMOD] -? 4
return-if NC? // ; Out of range?
HL -push <- cls_table
jump_table()
HL -pop
return
data cls_table = word [ /*local*/
cls_screen0
cls_screen1
cls_screen2
cls_screen3
]
}
proc cls_screen0() {
@[LINLEN] -? 40
BC <- (40 * 24)
JR C? cls_text
BC <- (80 * 24)
JR cls_text
}
proc cls_screen1() {
BC <- (32 * 24)
fallthrough
}
proc cls_text() {
HL <- [NAMBAS]
A <- 0x20
filvrm()
A <- 1
HL <- LINTTB
A -> [HL]
DE <- (LINTTB + 1)
BC <- 23
LDIR
JP chput_ctrl_home
}
proc cls_screen2() {
A ^ A
BC <- 0x1800
HL <- [CGPBAS]
L <- A
BC -push
filvrm()
BC -pop
A <- [BAKCLR]
HL <- [GRPCOL]
JP filvrm
}
proc cls_screen3() {
@[BAKCLR] & 0x0f -> B <* 4 | B
BC <- 0x0800
HL <- [CGPBAS]
JP filvrm
}
// ; $0105 GETPAT
// ; Function : Returns current pattern of a character
// ; Input : A - ASCII code of character
// ; Output : Pattern in PATWRK starting from address #FC40
// ; Registers: All
// ; Remark : Same as routine in MSX1-BIOS, but there it doesn't exist as
// ; a BIOS-call
proc getpat() {
BC <- [(CGPNT + 1)]
L <- A
H <- 0
HL + HL + HL + HL + BC
B <- 8
DE <- PATWRK
getpat_loop: /*local*/
BC -push
DE -push
HL -push
A <- [CGPNT]
rdslt()
HL -pop
DE -pop
BC -pop
A -> [DE]
DE ++
HL ++
DJNZ getpat_loop
return
}
// ;--------------------------------
// ; $00FC RIGHTC
// ; Function : Shifts screenpixel to the right
// ; Registers: AF
// ; NOTE : This implementation is still a stub!
proc rightc() {
HL -push
AF -push
HL <- rightc_text
print_debug()
AF -pop
HL -pop
return
data rightc_text = byte [ /*local*/
"RIGHTC" 0
]
}
// ;--------------------------------
// ; $00FF LEFTC
// ; Function : Shifts screenpixel to the left
// ; Registers: AF
// ; NOTE : This implementation is still a stub!
proc leftc() {
HL -push
AF -push
HL <- leftc_text
print_debug()
AF -pop
HL -pop
return
data leftc_text = byte [ /*local*/
"LEFTC" 0
]
}
// ;--------------------------------
// ; $0102 UPC
// ; Function : Shifts screenpixel up
// ; Registers: AF
// ; NOTE : This implementation is still a stub!
proc upc() {
HL -push
AF -push
HL <- upc_text
print_debug()
AF -pop
HL -pop
return
data upc_text = byte [ /*local*/
"UPC" 0
]
}
// ;--------------------------------
// ; $0105 TUPC
// ; Function : Tests whether UPC is possible, if possible, execute UPC
// ; Output : C-flag set if operation would end outside the screen
// ; Registers: AF
// ; NOTE : This implementation is still a stub!
proc tupc() {
HL -push
AF -push
HL <- tupc_text
print_debug()
AF -pop
HL -pop
return
data tupc_text = byte [ /*local*/
"TUPC" 0
]
}
// ;--------------------------------
// ; $0108 DOWNC
// ; Function : Shifts screenpixel down
// ; Registers: AF
// ; NOTE : This implementation is still a stub!
proc downc() {
HL -push
AF -push
HL <- downc_text
print_debug()
AF -pop
HL -pop
return
data downc_text = byte [ /*local*/
"DOWNC" 0
]
}
// ;--------------------------------
// ; $010B TDOWNC
// ; Function : Tests whether DOWNC is possible, if possible, execute DOWNC
// ; Output : C-flag set if operation would end outside the screen
// ; Registers: AF
// ; NOTE : This implementation is still a stub!
proc tdownc() {
HL -push
AF -push
HL <- tdownc_text
print_debug()
AF -pop
HL -pop
return
data tdownc_text = byte [ /*local*/
"TDOWNC" 0
]
}
// ;--------------------------------
// ; $010E SCALXY
// ; Function : Scales X and Y coordinates
// ; NOTE : This implementation is still a stub!
proc scalxy() {
BC <- [GRPACX]
DE <- [GRPACY]
return
}
data scalxy_text = byte [ /*unused*/
"SCALXY" 0
]
// ;--------------------------------
// ; $0111 MAPXYC
// ; Function : Places cursor at current cursor address
// ; Input : BC = X coordinate,DE=Y coordinate
// ; Register : AF,D,HL
// ; NOTE : This is a test version
proc mapxy() {
BC -push -> [GRPACX]
DE -> [GRPACY]
HL@[GRPACY] + HL + HL + HL
+ HL + HL
L <- 0x00
B <- 0x00
@0xff -> [CMASK]
@C & 0x07
JR Z? mapxy_mask_ed
B <- A
A <- 0xff
mapxy_mask_lp: /*local*/
A & A >*$ 1
DJNZ mapxy_mask_lp
A -> [CMASK]
mapxy_mask_ed: /*local*/
@C & 0xf8 -> C
B <- 0x00
HL + BC -> [CLOC]
BC -pop
return
}
data mapxy_text = byte [ /*unused*/
"MAPXY" 0
]
// ;--------------------------------
// ; $0114 FETCHC
// ; Function : Gets current cursor addresses mask pattern
// ; Output : HL - Cursor address
// ; A - Mask pattern
proc fetchc() {
A <- [CMASK]
HL <- [CLOC]
return
}
data fetchc_text = byte [ /*unused*/
"FETCHC" 0
]
// ;--------------------------------
// ; $0117 STOREC
// ; Function : Record current cursor addresses mask pattern
// ; Input : HL - Cursor address
// ; A - Mask pattern
// ; NOTE : This implementation is still a stub!
proc storec() {
HL -push
AF -push
HL <- storec_text
print_debug()
AF -pop
HL -pop
return
data storec_text = byte [ /*local*/
"STOREC" 0
]
}
// ;--------------------------------
// ; $011A SETATR
// ; Function : Set attribute byte
// ; NOTE : This implementation is still a stub!
proc setatr() {
HL -push
AF -push
HL <- setatr_text
print_debug()
AF -pop
HL -pop
return
data setatr_text = byte [ /*local*/
"SETATR" 0
]
}
// ;--------------------------------
// ; $011D READC
// ; Function : Reads attribute byte of current screenpixel
// ; NOTE : This implementation is still a stub!
proc readc() {
HL -push
AF -push
HL <- readc_text
print_debug()
AF -pop
HL -pop
return
data readc_text = byte [ /*local*/
"READC" 0
]
}
// ;--------------------------------
// ; $0120 SETC
// ; Function : Returns currenct screenpixel of specificed attribute byte
// ; NOTE : This implementation is still a stub!
proc setc() {
HL -push
AF -push
HL <- setc_text
print_debug()
AF -pop
HL -pop
return
data setc_text = byte [ /*local*/
"SETC" 0
]
}
// ;--------------------------------
// ; $0123 NSETCX
// ; Function : Set horizontal screenpixels
// ; NOTE : This implementation is still a stub!
proc nsetcx() {
HL -push
AF -push
HL <- nsetcx_text
print_debug()
AF -pop
HL -pop
return
data nsetcx_text = byte [ /*local*/
"NSETCX" 0
]
}
// ;--------------------------------
// ; $0126 GTASPC
// ; Function : Gets screen relations
// ; Output : DE, HL
// ; Registers: DE, HL
// ; NOTE : This implementation is still a stub!
proc gtaspc() {
HL -push
AF -push
HL <- gtaspc_text
print_debug()
AF -pop
HL -pop
return
data gtaspc_text = byte [ /*local*/
"GTASPC" 0
]
}
// ;--------------------------------
// ; $0129 PNTINI
// ; Function : Initalises the PAINT instruction
// ; NOTE : This implementation is still a stub!
proc pntini() {
HL -push
AF -push
HL <- pntini_text
print_debug()
AF -pop
HL -pop
return
data pntini_text = byte [ /*local*/
"PNTINI" 0
]
}
// ;--------------------------------
// ; $012C SCANR
// ; Function : Scans screenpixels to the right
// ; NOTE : This implementation is still a stub!
proc scanr() {
HL -push
AF -push
HL <- scanr_text
print_debug()
AF -pop
HL -pop
return
data scanr_text = byte [ /*local*/
"SCANR" 0
]
}
// ;--------------------------------
// ; $012F SCANL
// ; Function : Scans screenpixels to the left
// ; NOTE : This implementation is still a stub!
proc scanl() {
HL -push
AF -push
HL <- scanl_text
print_debug()
AF -pop
HL -pop
return
data scanl_text = byte [ /*local*/
"SCANL" 0
]
}
// ; vim:ts=8:expandtab:filetype=z8a:syntax=z8a:
// -- end: video.asm
// -- begin: debug.asm
// ; C-BIOS debug routines
// ; These routines should not be used in release builds of C-BIOS, but they can
// ; be useful for developers and testers.
// ;
// ; Copyright (c) 2004 Maarten ter Huurne. All rights reserved.
// ;
// ; Redistribution and use in source and binary forms, with or without
// ; modification, are permitted provided that the following conditions
// ; are met:
// ; 1. Redistributions of source code must retain the above copyright
// ; notice, this list of conditions and the following disclaimer.
// ; 2. Redistributions in binary form must reproduce the above copyright
// ; notice, this list of conditions and the following disclaimer in the
// ; documentation and/or other materials provided with the distribution.
// ;
// ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ;
// ;--------------------------------
// ; Print string to openMSX debug device as a separate line.
// ; Input: HL = address of zero-terminated string
// ; Changes: HL, AF
proc print_debug() {
@0x23 -out DBG_CTRL
CALL print_debug_asciiz
@0x00 -out DBG_CTRL
return
// ;--------------------------------
// ; Print string to openMSX debug device as part of an existing line.
// ; Input: HL = address of zero-terminated string
// ; Changes: HL, AF
print_debug_asciiz: /*local*/
A <- [HL]
HL ++
A | A
return-if Z?
A -out DBG_DATA
JR print_debug_asciiz
}
// ;--------------------------------
// ; Print nibble in hexidecimal format as part of an existing line.
// ; Input: A = nibble to print (bit 7-4 are ignored)
// ; Changes: AF
proc print_debug_hexnibble() {
A & 0x0f -? 10
JR NC? print_debug_hexnibble_letter
A + '0' -out DBG_DATA
return
print_debug_hexnibble_letter: /*local*/
A + ('A' - 10) -out DBG_DATA
return
}
// ;--------------------------------
// ; Print byte in hexidecimal format as part of an existing line.
// ; Input: A = byte to print
// ; Changes: AF
proc print_debug_hexbyte() {
AF -push
A >* 4
print_debug_hexnibble()
AF -pop
print_debug_hexnibble()
return
}
// ;--------------------------------
// ; Print word in hexidecimal format as part of an existing line.
// ; Input: HL = word to print
// ; Changes: HL, AF
proc print_debug_hexword() { /*unused*/
A <- H
print_debug_hexbyte()
A <- L
print_debug_hexbyte()
return
}
// -- end: debug.asm
// ; The game "Hacker" jumps directly to this location($0D02).
// ; Star force calls $0D0E.
org> 0x0d01
// ; for all wrong jumper,put RET instruction there
RET
POP IX // ; $0D02
POP IY
POP AF
POP BC
POP DE
POP HL
EXX
EX AF AF-
POP AF
POP BC
POP DE
POP HL
EI
RET
// ; $0000 CHKRAM
// ; Function : Tests RAM and sets RAM slot for the system
// ; Registers: All
// ; Remark : After this, a jump must be made to INIT, for further initialisation.
proc chkram() {
// ; Initialize interface
@0x82 -out PPI_REGS
@0x50 -out GIO_REGS
// ; Initialize memory bank
A ^ A -out MAP_REG4 ++
-out MAP_REG3 ++
-out MAP_REG2 ++
-out MAP_REG1
// ; Select the longest contiguous memory area for pages 3 and 2.
HL <- 0xffff // ; Keep the current best values in the
EXX // ; alternative register set (HL and BC).
// ; For each primary slot:
A -in PSL_STAT | 0xf0 -> B
chkram_pslot: /*local*/
// ; Select primary slot.
@B -out PSL_STAT
// ; For each secondary slot:
// ; Note that we do not check if the secondary slot is actually
// ; available: in case there is no secondary slot, we do the same
// ; test four times for the same primary slot.
@[SSL_REGS] -not | 0xf0 -> C
chkram_sslot: /*local*/
@C -> [SSL_REGS]
// ; Find the longest contiguous memory area for this slot
// ; configuration. Note that there is always ROM in pages
// ; 1 and 0.
HL <- 0xff00
chkram_find: /*local*/
@0x0f -> [HL] -? [HL]
JR NZ? chkram_find_end
A -not -> [HL] -? [HL]
JR NZ? chkram_find_end
H --
JR chkram_find
chkram_find_end: /*local*/
H ++
// ; Update the best values.
@H | A
JR Z? chkram_sslot_end
EXX
A -? H
JR C? chkram_update
JR Z? chkram_update
EXX
JR chkram_sslot_end
chkram_update: /*local*/
L <- 0 // ; Fix the L register to indicate that
H <- A // ; RAM is found.
EXX
A <- B
EXX
B <- A
EXX
A <- C
EXX
C <- A
EXX
chkram_sslot_end: /*local*/
@C - 0x10 -> C
JR NC? chkram_sslot
chkram_pslot_end: /*local*/
@B - 0x10 -> B
JR NC? chkram_pslot
// ; Select the longest contiguous memory area.
EXX
@L | A
JR Z? chkram_select
DE <- str_memory_err
JP print_error
chkram_select: /*local*/
@B -out PSL_STAT
@C -> [SSL_REGS]
// ; HL contains the start of the memory area (for BOTTOM variable).
EXX
// ;----------------------
// ; User interface
// ;----------------------
HL@0xf300 -> SP // ; set $F300 to stack pointer
CALL init_ram
CALL check_expanded
init_vdp()
EI
initio()
B <- 15
DE <- logo_ident
HL <- 0x8000
logo_check: /*local*/
BC -push
HL -push
DE -push
A <- [EXPTBL]
rdslt()
HL -pop
DE -pop
BC -pop
A -? [HL]
JR NZ? logo_none
DE <-> HL ++
HL ++
DJNZ logo_check
IX <- 0x8010
IY <- [(EXPTBL - 1)]
calslt()
JR logo_done
logo_none: /*local*/
@5 -> [BAKCLR] -> [BDRCLR]
init32()
HL <- str_proginfo
prn_text()
logo_done: /*local*/
EI
B <- 120
CALL wait_b
@COLOR_BORDER -> [BDRCLR]
@COLOR_BACK -> [BAKCLR]
@COLOR_FORE -> [FORCLR]
@29 -> [LINL32]
init32()
HL <- str_proginfo
prn_text()
CALL search_roms
CALL H_STKE
CALL run_basic_roms
// ; Set up hooks and system vars so NMS8250 disk ROM will try
// ; to load and execute the boot sector.
@1 -> [DEVICE] ^ A
// ; TODO: Find out or invent name for $FB29.
A -> [0xfb29]
// ; This is the hook the disk ROM uses for booting.
CALL H_RUNC
// ; We couldn't boot anything, instead show disk contents.
// ; TODO: This breaks boot of MG2, so disabled for now.
// ; jp disk_intr
// ; ret ; goto stack_error
HL <- str_nocart
prn_text()
JP hang_up_mode
data logo_ident = byte [ /*local*/
"C-BIOS Logo ROM"
]
// ;----------------------
// ; Search for any extension ROMs and initialize them.
search_roms: /*local*/
// ; Clear SLTATR.
HL <- SLTATR
DE <- (SLTATR + 1)
BC <- (4 * 4 * 4 - 1)
$(0) -> [HL]
LDIR
// ; Search for ROMs.
HL <- EXPTBL
A ^ A // ; A = input for RDSLT
search_roms_lp: /*local*/
HL -push
A | [HL]
search_roms_lp_sub: /*local*/
HL <- 0x4000
CALL search_roms_check
CALL Z? search_roms_init
HL <- 0x8000
CALL search_roms_check
CALL Z? search_roms_init
search_roms_no: /*local*/
A -bit? 7
JR Z? search_roms_next_slot
A + 4 // ; Select next subslot.
-bit? 4
JR Z? search_roms_lp_sub
search_roms_next_slot: /*local*/
HL -pop // ; Select next slot.
++
A ++ & 0x03
JR NZ? search_roms_lp
return
// ; Helper routine to read two bytes from a given slot.
search_roms_read: /*local*/
B <- A // ; Save the input for RDSLT in B.
rdslt()
HL ++
AF -push
A <- B
rdslt()
HL ++
D <- A
AF -pop
E <- A
A <- B
return
// ; Check whether the ROM is present or not.
search_roms_check: /*local*/
HL -push
CALL search_roms_read
HL <- 0x4241 // ; "AB"
dcompr() // ; ZF is set if the ROM is present.
A <- B
HL -pop
return
// ; Initialize the ROM and set up the related system variables.
search_roms_init: /*local*/
// ; Output a message to show that a ROM is found.
HL -push
AF -push
HL <- str_slot
prn_text()
AF -pop -push
B <- A
A & 0x03 + '0'
chput()
A <- B
B -bit? 7
JR Z? search_roms_init_skip
A <- '.'
chput()
@B >* 2 & 0x03 + '0'
chput()
search_roms_init_skip: /*local*/
A <- 0x0d
chput()
A <- 0x0a
chput()
AF -pop
HL -pop
// ; Read the initialization address and initialize the ROM.
HL ++ ++
CALL search_roms_address
JR Z? search_roms_init_statement
// ; Reg.C is using some games for slot number
C <- A
DE -push
IX -pop
AF -push
IY -pop
// ; Some cartridges have buggy initialisation code.
// ; By postponing the interrupt as long as possible,
// ; there is a better chance they will boot correctly.
// ; For example the game "Koronis Rift" depends on this.
search_roms_init_waitv: /*local*/
A -in 0x99 | A
JP M? search_roms_init_waitv
AF -push
HL -push
calslt()
DI
HL -pop
AF -pop
// ; Check if the addresses are valid.
search_roms_init_statement: /*local*/
C <- 0
CALL search_roms_address
JR Z? search_roms_init_device
C -set 5
search_roms_init_device: /*local*/
CALL search_roms_address
JR Z? search_roms_init_basic
C -set 6
search_roms_init_basic: /*local*/
CALL search_roms_address
JR Z? search_roms_init_variables
C -set 7
// ; Set up the related system variables.
search_roms_init_variables: /*local*/
B <- A // ; A = x000sspp
A & 0x0c -> E
@B <* 4 & 0x30 | E // ; A = 00ppss00
-> E
@H <* 2 & 0x03 | E // ; A = 00ppssPP
HL <- SLTATR
D <- 0
E <- A
HL + DE
C -> [HL]
A <- B
return
// ; Read an address and check whether it is valid or not.
search_roms_address: /*local*/
BC -push
CALL search_roms_read
@D | E // ; ZF is not set if the address is
A <- B // ; correct.
BC -pop
return
// ;----------------------
// ; Run any BASIC roms found.
run_basic_roms: /*local*/
HL <- SLTATR
B <- 64
run_basic_roms_lp: /*local*/
@[HL] -bit? 7
JR Z? run_basic_roms_next
HL -push <- str_basic
prn_text()
HL -pop
run_basic_roms_next: /*local*/
HL ++
DJNZ run_basic_roms_lp
return
// ;------------------------
// ; Initialize RAM
init_ram: /*local*/
// ; Initialize workarea
A <- 0x00
HL <- 0xf380
A -> [HL]
DE <- 0xf381
BC <- 0x0c7d
LDIR
// ; Initialize Disk work
A <- 0xc9
HL <- 0xf300
A -> [HL]
DE <- 0xf301
BC <- 0x7f
LDIR
// ; initialize hook area with $C9 (assembler code for ret)
A <- 0xc9 // ; ret code
HL <- H_KEYI
A -> [HL]
DE <- (H_KEYI + 1)
BC <- 0x024d // ; shouldn't this be $0235 ?
LDIR
// ; Initialize key matrix
A <- 0xff
HL <- OLDKEY
A -> [HL]
DE <- (OLDKEY + 1)
BC <- 21
LDIR
// ; Initialize Key buffer
A <- 0x00
HL <- KEYBUF
A -> [HL]
DE <- (KEYBUF + 1)
BC <- 39
LDIR
// ; Set address pointer
HL@KEYBUF -> [PUTPNT]
-> [GETPNT]
// ; ld hl,$8000
EXX
HL -> [BOTTOM] // ; Page1 and 2 is ROM,Page3 and 4 is RAM.
EXX
// ; I don't know exactly what is stored between $F168 and $F380,
// ; but the disk ROM needs some space there, so I'll just
// ; reserve all of it.
HL <- 0xf380 // ; was $F168, but needs to be changed by disk ROM
-> [HIMEM] // ; limit of usable memory
-> [STKTOP] // ; position of BASIC stack
// ;Transmit RDPRIM to RAM.
HL <- m_rdprim
DE <- 0xf380
BC <- (m_prim_end - m_rdprim)
LDIR
// ; Initialize table of screen 0
HL@0x00 -> [TXTNAM]
HL@0x0800 -> [TXTCGP]
// ; Initialize table of screen 1
HL@0x1800 -> [T32NAM]
HL@0x2000 -> [T32COL]
HL@0x00 -> [T32CGP]
HL@0x1b00 -> [T32ATR]
HL@0x3800 -> [T32PAT]
// ; Initialize table of screen 2
HL@0x1800 -> [GRPNAM]
HL@0x2000 -> [GRPCOL]
HL@0x00 -> [GRPCGP]
HL@0x1b00 -> [GRPATR]
HL@0x3800 -> [GRPPAT]
// ; Initialize table fo screen 3
HL@0x0800 -> [MLTNAM]
HL@0x00 -> [MLTCGP]
HL@0x1b00 -> [MLTATR]
HL@0x3800 -> [MLTPAT]
// ; Initialise QUETAB.
HL@QUETAB -> [QUEUES]
HL@VOICAQ
-> [(QUETAB + 0 * 6 + 4)]
HL@VOICBQ
-> [(QUETAB + 1 * 6 + 4)]
HL@VOICCQ
-> [(QUETAB + 2 * 6 + 4)]
@0x7f
-> [(QUETAB + 0 * 6 + 3)]
-> [(QUETAB + 1 * 6 + 3)]
-> [(QUETAB + 2 * 6 + 3)]
// ; other settings
@39 -> [LINL40]
A <- 32 // ; Set to 29 after splash screen.
-> [LINL32]
// ;TODO: Rely on call to INIT32 instead.
@[LINL32] -> [LINLEN]
@24 -> [CRTCNT]
@COLOR_BORDER -> [BDRCLR]
@COLOR_BACK -> [BAKCLR]
@COLOR_FORE -> [FORCLR]
@0xa0 -> [RG1SAV]
@[EXPTBL] -> [CGPNT]
HL@[4] -> [(CGPNT + 1)]
// ; set up hook
A <- 0xc3
HL@chput -> [(H_OUTD + 1)]
A -> [H_OUTD]
return
// ;----------------------
// ; Check which slots are expanded.
// ; Initialises EXPTBL for all 4 slots.
check_expanded: /*local*/
// ; Prepare to iterate over slots [0..3].
DI
HL <- EXPTBL
A -in PSL_STAT -> D // ; D = saved value from port $A8
& 0x3f -> C
check_expanded_lp: /*local*/
A -out PSL_STAT <- [SSL_REGS]
-not -> E // ; E = saved SSL value
// ; Test whether $0x is read back as complement.
A & 0x0f -> [SSL_REGS] -> B
@[SSL_REGS] -not -? B
JR NZ? check_expanded_not
// ; Test whether $5x is read back as complement.
@E & 0x0f | 0x50 -> [SSL_REGS]
-> B
@[SSL_REGS] -not -? B
JR NZ? check_expanded_not
// ; SSL register present -> slot expanded.
B <- 0x80
A <- E
JR check_expanded_next
check_expanded_not: /*local*/
// ; SSL register present -> slot expanded.
B <- 0x00
A <- E // ; E = saved SSL value
-not // ; not SSL -> back to original
check_expanded_next: /*local*/
A -> [SSL_REGS] <- D // ; D = saved value from port $A8
-out PSL_STAT
B -> [HL]
HL ++
// ; Next slot.
@C + 0x40 -> C
JR NC? check_expanded_lp
EI
return
// ;------------------------
// ; wait routine
// ; caution,already EI when call the rouine
// ; B = frequency of loop
wait_b: /*local*/
HALT
DJNZ wait_b
return
}
// ;------------------------
// ;prn_text
// ; HL = string with null termination
proc prn_text() {
@[SCRMOD] -? 5
JR NC? prn_text_graph
prn_text_char: /*local*/
@[HL] | A
return-if Z?
chput()
HL ++
JR prn_text_char
prn_text_graph: /*local*/
@[HL] | A
return-if Z?
IX <- 0x89
extrom()
HL ++
JR prn_text_graph
}
// ;--------------------------------
// ; Determine bytes per line in the current text mode.
// ; Input: SCRMOD, LINLEN
// ; Output: C = number of bytes per line
// ; Changes: AF
proc text_bytes_per_line() {
C <- 32 // ; text32
@[SCRMOD] | A
return-if NZ?
C <- 40 // ; text40
@[LINLEN] -? 41
return-if C?
C <- 80 // ; text80
return
}
// ;--------------------------------
// ; Calculate the VRAM address that corresponds to the current cursor position.
// ; Input: CSRX, CSRY
// ; Output: HL = VRAM address
// ; Changes: none
proc curs2hl() {
BC -push
AF -push
text_bytes_per_line()
// ; Calculate left border.
@[LINLEN] -neg + C // ; A = bytes_per_line - LINLEN
++ // ; round up
>>> 1 // ; A = A / 2
-> L // ; L = size of left border
// ; Add X coordinate.
@[CSRX] -- // ; from 1-based to 0-based
+ L // ; add border size
-> L
// ; Convert to 16-bits counters.
H@0 -> B
// ; Add Y * bytes_per_line.
@[CSRY] -- // ; from 1-based to 0-based
curs2hl_mult_loop: /*local*/
A >>> 1
JR NC? curs2hl_mult_skip
HL + BC
curs2hl_mult_skip: /*local*/
C << 1 // ; BC = BC * 2
B <*$ 1
A | A
JR NZ? curs2hl_mult_loop
// ; Add base address.
BC <- [NAMBAS]
HL + BC
AF -pop
BC -pop
return
}
// ;---------------------------
// ; Subroutines
// ;---------------------------
// ; the extensive descriptions were taken with permission from http://map.tni.nl/
// ;-------------------------------------
// ;0008h SYNCHR
// ;Function: tests whether the character of [HL] is the specified character
// ; if not, it generates SYNTAX ERROR, otherwise it goes to CHRGTR
// ; (#0010)
// ;Input: set the character to be tested in [HL] and the character to be
// ; compared next to RST instruction which calls this routine (inline
// ; parameter)
// ;Output: HL is increased by one and A receives [HL], When the tested character
// ; is numerical, the CY flag is set the end of the statement (00h or
// ; 3Ah) causes the Z flag to be set
// ;Registers: AF, HL
// ;NOTE: this implementation is still a stub!
proc synchr() {
HL -push
AF -push
HL <- synchr_text
print_debug()
AF -pop
HL -pop
return
data synchr_text = byte [ /*local*/
"SYNCHR" 0
]
}
// ;-------------------------------------
// ; $0010 CHRGTR
// ; Read the next program character.
// ; In: HL = pointer to the program text
// ; Out: A = the next program character
// ; HL = pointer to the next program character
// ; ZF = set if it's the end of statement
// ; CF = set if it's a number
// ; Changes: AF, HL
proc chrgtr() {
CALL H_CHRG
chrgtr_lp: /*local*/
A <- [HL]
HL ++
// ; Check for the end of statement.
A -? 0x00 // ; end of line
return-if Z?
A -? 0x3a // ; statement separator
return-if Z?
// ; Check for digits.
A -? '0'
JR C? chrgtr_no_digit
A -? ('9' + 1)
return-if C?
chrgtr_no_digit: /*local*/
// ; Skip whitespace.
A -? 0x20 // ; space
JR Z? chrgtr_lp
A -? 0x09 // ; tab
JR Z? chrgtr_lp
// ; Otherwise it's a normal program character.
A | A // ; Clear CF and ZF.
return
}
// ;-------------------------------------
// ; $0018 OUTDO
// ; Function : Output to current outputchannel (printer, diskfile, etc.)
// ; Input : A - PRTFIL, PRTFLG
// ; Remark : Used in basic, in ML it's pretty difficult.
proc outdo() {
AF -push
CALL H_OUTD // ; H_OUTD does the real outputting
AF -pop
return
}
// ;--------------------------------
// ; $0020 DCOMPR
// ; Function : Compared HL to DE
// ; Output : flags influenced like CP instruction
// ; Registers: A
proc dcompr() {
@H -? D
return-if NZ?
@L -? E
return
}
// ;--------------------------------
// ; $0028 GETYPR
// ; Function : Returns Type of DAC
// ; Input : VALTYP(F663)
// ; Output : C, Z, S
// ; C Z S Type VALTYP
// ; low - - double 8
// ; high high low string 3
// ; high low high integer 2
// ; high low low float 4
// ; Registers: AF
// ;NOTE: this implementation is still a stub!
proc getypr() {
HL -push
AF -push
HL <- getypr_text
print_debug()
AF -pop
HL -pop
return
data getypr_text = byte [ /*local*/
"GETYPR" 0
]
}
// ;--------------------------------
// ; $0030 CALLF
proc callf() {
AF <-> AF-
EXX
HL -pop // ; Get data from return address.
A <- [HL]
HL ++
E <- [HL]
HL ++
D <- [HL]
HL ++
DE -push // ; IX = call address
IX -pop
AF -push // ; IY = slot
IY -pop
HL -push // ; Update return address.
AF <-> AF-
EXX
JP calslt // ; Perform inter-slot call.
}
// ;--------------------------------
// ; $003B INITIO
// ;Function: Initialises the device
// ;Registers: All
proc initio() {
E <- 0x8f // ; strobe off, triggers on
A <- 0x0f
wrtpsg()
// ; TODO: What else must be initialized here?
JP gicini
}
// ;--------------------------------
// ; $003E INIFNK
// ; Function : Initialises the contents of the function keys
// ; Registers: All
// ;NOTE: this implementation is still a stub!
proc inifnk() {
HL -push
AF -push
HL <- inifnk_text
print_debug()
AF -pop
HL -pop
return
data inifnk_text = byte [ /*local*/
"INIFNK" 0
]
}
// ;--------------------------------
// ; $0099 STRTMS
// ; Function : Tests whether the PLAY statement is being executed as a background
// ; task. If not, begins to execute the PLAY statement
// ; Registers: All
// ;NOTE: this implementation is still a stub!
proc strtms() {
HL -push
AF -push
HL <- strtms_text
print_debug()
AF -pop
HL -pop
return
data strtms_text = byte [ /*local*/
"STRTMS" 0
]
}
// ;--------------------------------
// ; $009C CHSNS
// ; Function : Tests the status of the keyboard buffer
// ; Output : Z-flag set if buffer is filled
// ; Registers: AF
proc chsns() {
EI
HL -push
DE -push
HL <- [GETPNT]
DE <- [PUTPNT]
RST 0x20
A <- 0xff
JR NZ? chsns_inbuf
A ^ A
chsns_inbuf: /*local*/
DE -pop
HL -pop
return
}
// ;--------------------------------
// ; $009F CHGET
// ; Function : One character input (waiting)
// ; Output : A - ASCII-code of the input character
// ; Registers: AF
proc chget() {
CALL H_CHGE
HL -push
DE -push
chget_wait: /*local*/
HL <- [GETPNT]
DE <- [PUTPNT]
RST 0x20
JR NZ? chget_char
EI
HALT
JR chget_wait
chget_char: /*local*/
A <- [HL] // ; HL = (GETPNT)
AF -push
HL ++
// ; See comment in keyint (below label key_store).
A <- L
// ; Currently, tniASM doesn't support "&" and SjASM doesn't
// ; support "AND", so we have to hardcode the result.
// ; cp $00FF & (KEYBUF + 40)
A -? 0x18
JR NZ? chget_nowrap
HL <- KEYBUF
chget_nowrap: /*local*/
HL -> [GETPNT]
AF -pop
DE -pop
HL -pop
return
}
// ;--------------------------------
// ; $00A2 CHPUT
// ; Input: A = character code
// ; Changes: none
// -- begin: chput.asm
// ; CHPUT routine for C-BIOS
// ;
// ; Copyright (c) 2006 Eric Boon. All rights reserved.
// ;
// ; Redistribution and use in source and binary forms, with or without
// ; modification, are permitted provided that the following conditions
// ; are met:
// ; 1. Redistributions of source code must retain the above copyright
// ; notice, this list of conditions and the following disclaimer.
// ; 2. Redistributions in binary form must reproduce the above copyright
// ; notice, this list of conditions and the following disclaimer in the
// ; documentation and/or other materials provided with the distribution.
// ;
// ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ;
// ; -------------------------------------
// ; $00A2 CHPUT
// ; Function : Output character in A to screen
// ; Input : A = character code
// ; Output : -
// ; Changes : -
proc chput() {
HL -push // ; save all regs
DE -push
BC -push
AF -push
CALL H_CHPU // ; call hook
A <- [SCRMOD] // ; this only works in
-? 2 // ; screen modes 0 and 1
JR NC? chput_exit
AF -pop // ; restore char to put in A
-push
chput_remove_cursor()
AF -pop // ; restore char to put in A
-push
CALL chput_decode_char
chput_restore_cursor()
A <- [CSRX] // ; CSRX -> TTYPOS
-> [TTYPOS]
chput_exit: /*local*/
AF -pop
BC -pop
DE -pop
HL -pop
return
// ; -- decode character in A
chput_decode_char: /*local*/
cnvchr() // ; Graphic character?
return-if NC? // ; NC -> graphic extension hdr
JR Z? chput_putchar // ; C,Z -> graphic character
AF -push // ; (C,NZ -> normal char)
A <- [ESCCNT] // ; ESC sequence?
| A
JP NZ? chput_escape
AF -pop
A -? 0x20 // ; Control code?
JR C? chput_ctrl_search
A -? 127 // ; DEL?
JP Z? chput_erase
fallthrough
}
// ; -- print a normal character and move cursor to next position
proc chput_putchar() {
curs2hl() // ; output character to screen
wrtvrm()
HL <- [CSRY] // ; h = (CSRX), l = (CSRY)
A <- [LINLEN]
H ++
A -? H
JR C? chput_continue_line
HL -> [CSRY]
return
chput_continue_line: /*local*/
DE <- (LINTTB - 1) // ; make logical line continue
H <- 0
HL + DE
A ^ A -> [HL]
HL <- [CSRY] // ; move cursor to start of
chput_ctrl_cr() // ; new line
JP chput_ctrl_lf
}
// ; -- Handle control code
proc chput_ctrl_search() {
B <- 12
HL <- chput_ctrl_table
JP search_table
}
// ; -- Fill with spaces until next TAB stop
proc chput_ctrl_tab() {
A <- 0x20
chput_putchar()
@[CSRX] & 7 -? 1
JR NZ? chput_ctrl_tab
return
}
// ; -- Line Feed.
proc chput_ctrl_lf() {
HL <- [CSRY]
A <- [CRTCNT]
L ++
A -? L
JR NC? chput_ctrl_lf_done
HL -push
CALL chput_ctrl_home // ; home cursor
chput_esc_m() // ; delete top line (scroll!)
HL -pop
L --
chput_ctrl_lf_done: /*local*/
HL -> [CSRY]
return
}
// ; -- Home cursor
chput_ctrl_home:
proc chput_esc_h() {
HL@0x0101 -> [CSRY]
return
}
// ; -- Form Feed / Cls
const chput_ctrl_ff = cls
const chput_esc_e = cls
const chput_esc_j = cls
// ; -- Clear till end of screen
proc chput_esc_jj() {
chput_esc_k() // ; clear till end of line
HL <- [CSRY] // ; save current cursor pos
-push
chput_ctrl_cr() // ; move to line start
chput_esc_jj_loop: /*local*/
A <- [CSRY] // ; while no at end of screen
HL <- CRTCNT
A -? [HL]
JR NC? chput_esc_jj_done
chput_ctrl_lf() // ; move to next line
chput_esc_k() // ; clear till end of line
JR chput_esc_jj_loop // ; loop
chput_esc_jj_done: /*local*/
HL -pop // ; restore cursor pos
-> [CSRY]
return
}
// ; -- Carriage return
proc chput_ctrl_cr() {
@1 -> [CSRX]
return
}
// ; -- Escape
proc chput_ctrl_esc() {
@0xff -> [ESCCNT]
return
}
// ; -- Cursor right
proc chput_ctrl_right() {
A <- [CSRX]
HL <- LINLEN
A -? [HL]
JR NC? chput_ctrl_right_next
A ++
JR chput_right_left_ok
chput_ctrl_right_next: /*local*/
A <- [CSRY]
HL <- CRTCNT
A -? [HL]
return-if NC?
A ++ -> [CSRY]
JR chput_ctrl_cr
}
// ; -- Cursor left
chput_ctrl_bs:
proc chput_ctrl_left() {
@[CSRX] --
JR NZ? chput_right_left_ok
@[CSRY] --
return-if Z?
A -> [CSRY] <- [LINLEN]
fallthrough
}
proc chput_right_left_ok() {
A -> [CSRX]
return
}
// ; -- Cursor up
chput_ctrl_up:
proc chput_esc_a() {
@[CSRY] --
return-if Z?
A -> [CSRY]
return
}
// ; -- Cursor down
chput_ctrl_down:
proc chput_esc_b() {
A <- [CSRY]
HL <- CRTCNT
A -? [HL]
return-if NC?
A ++ -> [CSRY]
return
}
// ; -- Handle ESC mode (ESCCNT in A and != 0)
proc chput_escape() {
B <- A // ; b := (ESCCNT)
A ++ // ; (ESCCNT) == -1 ?
JR NZ? chput_escape_1
A -> [ESCCNT]
AF -pop // ; restore character in A
B <- 15 // ; search in table
HL <- chput_esc_table
JP search_table
chput_escape_1: /*local*/ // ; ----------------------------
AF -pop
DJNZ chput_escape_2
// ; -- ESCCNT == 1: 'ESC x <n>'
C <- 0 // ; CSTYLE/CSRSW := 0
JR chput_esc_xy
chput_escape_2: /*local*/ // ; ----------------------------
DJNZ chput_escape_3
// ; -- ESCCNT == 2: 'ESC y <n>'
C <- 1 // ; CSTYLE/CSRSW := 1
chput_esc_xy: /*local*/
A -? '4'
JR Z? chput_esc_xy_4
A -? '5'
JR Z? chput_esc_xy_5
JR chput_escape_reset
chput_esc_xy_4: /*local*/
@C -> [CSTYLE]
JR chput_escape_reset
chput_esc_xy_5: /*local*/
@C -> [CSRSW]
JR chput_escape_reset
chput_escape_3: /*local*/ // ; ----------------------------
DJNZ chput_escape_4
// ; -- ESCCNT == 3: 'ESC Y <n> <m>'
B <- 0x1f
A - B -> [CSRX]
JR chput_escape_reset
chput_escape_4: /*local*/ // ; ----------------------------
DJNZ chput_escape_reset
// ; -- ESCCNT == 4: 'ESC Y <n>'
B <- 0x1f
A - B -> [CSRY]
A <- 3
JR chput_escape_set
}
// ; -- ESCCNT := 1
proc chput_esc_x() {
A <- 1
JR chput_escape_set
}
// ; -- ESCCNT := 2
proc chput_esc_y() {
A <- 2
JR chput_escape_set
}
// ; -- ESCCNT := 4
proc chput_esc_yy() {
A <- 4
JR chput_escape_set
}
proc chput_escape_reset() {
A ^ A
fallthrough
}
proc chput_escape_set() {
A -> [ESCCNT]
return
}
// ; -- Cursor right, no wrap
proc chput_esc_c() {
A <- [CSRX]
HL <- LINLEN
A -? [HL]
return-if NC?
A ++ -> [CSRX]
return
}
// ; -- Cursor left, no wrap
proc chput_esc_d() {
@[CSRX] --
return-if Z?
A -> [CSRX]
return
}
// ; -- clear line
proc chput_esc_l() {
chput_ctrl_cr()
fallthrough
}
// ; -- Clear till end of line
proc chput_esc_k() {
HL <- (LINTTB - 1) // ; update LINTTB
@[CSRY] -> E
D <- 0
HL + DE
// ; a != 0, which is OK
A -> [HL] <- [LINLEN] ++ // ; because CSRX is 1-based
HL <- CSRX
A - [HL] -> C
B <- 0
A <- 32
curs2hl()
JP filvrm
}
// ; -- Insert line
proc chput_esc_ll() {
chput_ctrl_cr() // ; move to start of line
HL <- [CSRY] // ; save current cursor pos
-push
B <- L
@[CRTCNT] -> [CSRY] - B -> B
B ++
A <- [CSRY]
JR chput_esc_ll_loop_end
chput_esc_ll_loop: /*local*/
curs2hl()
DE <-> HL
A -- -> [CSRY]
curs2hl()
chput_copy_line()
chput_esc_ll_loop_end: /*local*/
DJNZ chput_esc_ll_loop
HL -pop // ; restore cursor position
-> [CSRY]
H <- 0
A <- [CRTCNT] // ; update LINTTB
-> D // ; DE := (CRTCNT)
E <- 0
A - L // ; BC := (CRTCNT) - (CSRY) - 1
-- -> C
B <- 0
HL <- (LINTTB - 1) // ; DE := LINTTB + (CRTCNT)
+ DE
DE <-> HL
H <- D // ; HL := DE - 1
L <- E
HL --
LDDR
JP chput_esc_k
}
// ; -- Delete line (and scroll rest up)
proc chput_esc_m() {
chput_ctrl_cr() // ; move to start of line
HL@[CSRY] -push // ; save cursor pos
B <- L
@[CRTCNT] - B -> B
B ++
A <- [CSRY]
JR chput_esc_m_loop_end
chput_esc_m_loop: /*local*/
curs2hl() // ; Copy 1 line:
DE <-> HL // ; de = dest in VRAM
A ++ // ; next line
-> [CSRY]
curs2hl() // ; hl = src in VRAM
chput_copy_line()
chput_esc_m_loop_end: /*local*/
DJNZ chput_esc_m_loop // ; endloop
chput_esc_k() // ; clear till end of line
HL -pop // ; restore cursor position
-> [CSRY]
H <- 0 // ; update LINTTB
A <- [CRTCNT] // ; BC := (CRTCNT) - (CRSY) - 1
- L -- -> C
B <- 0
DE <- (LINTTB - 1) // ; DE := LINTTB + (CSRY)
HL + DE
D <- H
E <- L
HL ++ // ; HL := DE + 1
LDIR
return
}
// ; -- Copy line: from HL to DE
proc chput_copy_line() {
AF -push
BC -push
B <- 0
@[LINLEN] -> C
CALL chput_copy_line_copy
BC -pop
AF -pop
return
chput_copy_line_copy: /*local*/
HL -push
DE -push
BC -push
DE <- LINWRK
ldirmv()
BC -pop
DE -pop -push
BC -push
HL <- LINWRK
ldirvm()
BC -pop
HL -pop + BC
DE <-> HL
HL -pop + BC
return
}
// ; -- Erase
proc chput_erase() {
@[CSRX] -? 1
return-if Z?
A <- 32
chput_putchar()
JP chput_ctrl_left
}
// ; -- disable cursor
proc chput_remove_cursor() {
A <- [CSRSW] // ; Cursor visible?
-? 1
return-if NZ?
A <- [SCRMOD] // ; Are we in text mode?
-? 2
return-if NC?
A <- [CURSAV] // ; get saved character
curs2hl() // ; and drop it at the
JP wrtvrm
}
// ; -- enable cursor
proc chput_restore_cursor() {
A <- [CSRSW] // ; Cursor visible?
-? 1
return-if NZ?
@[SCRMOD] -? 2
return-if NC?
curs2hl() // ; get character at cursor
rdvrm() // ; and store at CURSAV
A -> [CURSAV] & A // ; reset carry
D <- 0 // ; de := 8 * a
E@A <*$ 1
D <*$ 1
E <*$ 1
D <*$ 1
E <*$ 1
D <*$ 1
A ^ A // ; get pattern table address
HL <- SCRMOD
A -? [HL]
JR NZ? chput_restore_cursor_t32
HL <- [TXTCGP]
JR chput_restore_cursor_getpattern
chput_restore_cursor_t32: /*local*/
HL <- [T32CGP]
chput_restore_cursor_getpattern: /*local*/
HL -push + DE // ; add offset of character
DE <- LINWRK // ; copy pattern to LINWRK
BC <- 8
ldirmv()
A <- [CSTYLE] // ; depending on CSTYLE
-? 0
JR NZ? chput_restore_cursor_ins
HL <- LINWRK // ; invert the complete pattern
B <- 8
JR chput_restore_cursor_invert
chput_restore_cursor_ins: /*local*/
HL <- (LINWRK + 6) // ; or only the lower 2 lines
B <- 2
chput_restore_cursor_invert: /*local*/
A <- [HL] // ; invert!
-not -> [HL]
HL ++
DJNZ chput_restore_cursor_invert
HL -pop // ; copy inverted pattern to
DE <- (255 * 8) // ; pattern 255
HL + DE
DE <-> HL
HL <- LINWRK
BC <- 8
ldirvm()
curs2hl() // ; place char 255 at cursor pos
A <- 255
JP wrtvrm
}
// ; -- Control character search table
data chput_ctrl_table = byteword [
{ 7 beep } // ; chput_ctrl_beep
{ 8 chput_ctrl_bs }
{ 9 chput_ctrl_tab }
{ 10 chput_ctrl_lf }
{ 11 chput_ctrl_home }
{ 12 chput_ctrl_ff }
{ 13 chput_ctrl_cr }
{ 27 chput_ctrl_esc }
{ 28 chput_ctrl_right }
{ 29 chput_ctrl_left }
{ 30 chput_ctrl_up }
{ 31 chput_ctrl_down }
]
// ; -- Escape character search table
data chput_esc_table = byteword [
{ 'j' chput_esc_j }
{ 'E' chput_esc_e }
{ 'K' chput_esc_k }
{ 'J' chput_esc_jj }
{ 'l' chput_esc_l }
{ 'L' chput_esc_ll }
{ 'M' chput_esc_m }
{ 'Y' chput_esc_yy }
{ 'A' chput_esc_a }
{ 'B' chput_esc_b }
{ 'C' chput_esc_c }
{ 'D' chput_esc_d }
{ 'H' chput_esc_h }
{ 'x' chput_esc_x }
{ 'y' chput_esc_y }
]
// ; vim:ts=8:expandtab:filetype=z8a:syntax=z8a:
// -- end: chput.asm
// ;--------------------------------
// ; $00A5 LPTOUT
// ; Function : Sends one character to printer
// ; Input : A - ASCII-code of character to send
// ; Output : C-flag set if failed
// ; Registers: F
proc lptout() {
CALL H_LPTO
AF -push
lptout_wait: /*local*/
breakx()
JR C? lptout_abort
lptstt()
JR Z? lptout_wait
AF -pop
JR lptout_write
lptout_abort: /*local*/
A <- 13
CALL lptout_write
A ^ A -> [LPTPOS]
AF -pop
SCF
return
lptout_write: /*local*/
AF -push
A -out PRN_DATA <- 0
-out PRN_STAT -not
-out PRN_STAT
AF -pop
A & A
return
}
// ;--------------------------------
// ; $00A8 LPTSTT
// ; Function : Tests printer status
// ; Output : A - #FF and Z-flag reset if printer is ready
// ; #00 and Z-flag set if not ready
// ; Registers: AF
proc lptstt() {
CALL H_LPTS
A -in PRN_STAT >*$ 2
A <- 0xff
JR NC? lptstt_end
A -not
lptstt_end: /*local*/
A & A
return
}
// ;--------------------------------
// ; $00AB CNVCHR
// ; Function : tests for the graphic header and transforms the code
// ; Input : A - charactercode
// ; GRPHED(FCA6): indicates if previous char was an extension code
// ; Output: C-flag Z-flag A
// ; if byte is extension byte low high 1
// ; if byte is normal ASCII high low ASCII code
// ; if byte is graphical extension high high extension code
// ; GRPHED is updated
// ; Registers: AF
proc cnvchr() {
HL -push
AF -push
HL <- GRPHED
A ^ A -? [HL] -> [HL] // ; reset GRPHED in advance
JR NZ? cnvchr_handlegfx
AF -pop // ; we're not in graphic mode
A -? 1 // ; graphic header?
JR NZ? cnvchr_normal
A -> [HL] // ; yes! -> Set GRPHED
JR cnvchr_normal_exit // ; we've got NC and Z - perfect!
cnvchr_handlegfx: /*local*/
AF -pop
A -? 0x40
JR C? cnvchr_nogfx
A -? 0x60
JR NC? cnvchr_nogfx
A - 0x40 // ; graphic char
-? A // ; set Z (and NC)
JR cnvchr_normal
cnvchr_nogfx: /*local*/
A -? 0x50 // ; A is definitely not #50
// ; so this sets NZ :-)
cnvchr_normal: /*local*/
SCF // ; NZ/Z already ok, now set C
cnvchr_normal_exit: /*local*/
HL -pop
return
}
// -- begin: inlin.asm
// ; INLIN/PINLIN/QINLIN routines for C-BIOS
// ;
// ; Copyright (c) 2007 Eric Boon. All rights reserved.
// ;
// ; Redistribution and use in source and binary forms, with or without
// ; modification, are permitted provided that the following conditions
// ; are met:
// ; 1. Redistributions of source code must retain the above copyright
// ; notice, this list of conditions and the following disclaimer.
// ; 2. Redistributions in binary form must reproduce the above copyright
// ; notice, this list of conditions and the following disclaimer in the
// ; documentation and/or other materials provided with the distribution.
// ;
// ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ;
// ;--------------------------------
// ; $00AE PINLIN
// ; Function : Stores in the specified buffer the character codes input
// ; until the return key or STOP key is pressed
// ; Output : HL - for the starting address of the buffer -1
// ; C-flag set when it ends with the STOP key
// ; Registers: All
// ; TODO: call H_PINL
proc pinlin() {
CALL H_PINL
A <- [AUTFLG] // ; If AUTO is active
& A
JP Z? inlin // ; then start line input
A <- 1 // ; else set cursor
-> [CSRX] // ; to left border first
JP inlin // ; and then start line input
}
// ;--------------------------------
// ; $00B4 QINLIN
// ; Function : Prints a questionmark and one space and continues with INLIN
// ; Output : HL - for the starting address of the buffer -1
// ; C-flag set when it ends with the STOP key
// ; Registers: All
data qinlin_prompt = byte [
"? " 0
]
proc qinlin() {
CALL H_QINL
HL <- qinlin_prompt
prn_text()
fallthrough
}
// ; continue with inlin
// ;--------------------------------
// ; $00B1 INLIN
// ; Function : Main line input routine
// ; Output : HL - for the starting address of the buffer -1
// ; C-flag set when it ends with the STOP key
// ; Registers: All
proc inlin() {
HL <- [CSRX] // ; loads CSRX and CSRY
-> [FSTPOS] // ; save in FSTPOS
DE <- (LINTTB - 2) // ; break logical line
H <- 0 // ; above cursor pos
A <- L
HL + DE
A -> [HL]
inlin_loop: /*local*/
chget() // ; get a character from the kbd
A -? 0x7f
JP Z? inlin_del
A -? 0x20
JR NC? inlin_printable
B <- 20
HL <- inlin_table
jump_table()
A ^ A // ; we just put out a ctrl char
-> [INSFLG] // ; switch insert mode off
-> [CSTYLE]
JR inlin_loop
inlin_printable: /*local*/ // ; else...
AF -push
@[INSFLG] & A
CALL NZ? inlin_insert
AF -pop
RST 0x18
JR inlin
// ; ----------------------------------------------
inlin_insert: /*local*/
chput_remove_cursor()
HL <- [CSRY] // ; save cursorpos
-> [TEMP2]
A <- ' ' // ; oldchar = space
-> [TEMP]
inlin_insert_loop: /*local*/ // ; REPEAT
curs2hl() // ; get char under curpos
rdvrm()
A -? ' ' // ; IF is space
JR NZ? inlin_insert_cont
HL <- [CSRY] // ; AND at end of line
@[LINLEN] -? H
JR NZ? inlin_insert_cont1
H <- 0 // ; AND logical line does
DE <- (LINTTB - 1) // ; not continue
HL + DE
@[HL] | A
JR Z? inlin_insert_cont1
A <- [TEMP] // ; THEN
curs2hl()
wrtvrm() // ; put old char
HL <- [TEMP2] // ; restore cursor pos
-> [CSRY]
return
JP chput_restore_cursor // ; and exit
inlin_insert_cont1: /*local*/
A <- ' '
inlin_insert_cont: /*local*/
AF -push // ; ELSE
A <- [TEMP] // ; put old char
RST 0x18
AF -pop
A -> [TEMP] // ; oldchar = character read
JR inlin_insert_loop // ; ENDREP
// ; ----------------------------------------------
inlin_wback: /*local*/
return
// ; ----------------------------------------------
inlin_break: /*local*/
SCF // ; C
HL -pop // ; do not return to INLIN
return // ; but to caller of INLIN
// ; ----------------------------------------------
inlin_clear: /*local*/
return
// ; ----------------------------------------------
inlin_wfwd: /*local*/
return
// ; ----------------------------------------------
inlin_bs: /*local*/
return
// ; ----------------------------------------------
inlin_cr: /*local*/
return
// ; ----------------------------------------------
inlin_end: /*local*/
A ^ A // ; NZ, NC
HL -pop // ; do not return to INLIN
return // ; but to caller of INLIN
// ; ----------------------------------------------
inlin_ins: /*local*/
return
// ; ----------------------------------------------
inlin_clrlin: /*local*/
return
// ; -- ESCAPE
inlin_esc: /*local*/
return // ; Do nothing
// ; -- DELETE
inlin_del: /*local*/
return
// ; -- Jump table. Control chars not handled in one of the routines above
// ; are simply forwarded to OUTDO
data inlin_table = word [ /*local*/
0x18 // ; @
0x18 // ; A -
inlin_wback // ; B word back
inlin_break // ; C stop, abort, quit
0x18 // ; D
inlin_clear // ; E: clear to end of line
inlin_wfwd // ; F: word fwd
0x18 // ; G
inlin_bs // ; H BACKSP: erase char left
0x18 // ; I
0x18 // ; J
0x18 // ; K
0x18 // ; L
inlin_cr // ; M ENTER : confirm, yes, ok
inlin_end // ; N to end of line
0x18 // ; O
0x18 // ; P
0x18 // ; Q
inlin_ins // ; R INSERT: toggle insert mode
0x18 // ; S
0x18 // ; T
inlin_clrlin // ; U clear line
0x18 // ; V
0x18 // ; W
0x18 // ; X
0x18 // ; Y
0x18 // ; Z
inlin_esc // ; ESCAPE: ignore
0x18 // ; (28)
0x18 // ; (29)
0x18 // ; (30)
0x18 // ; (31)
]
}
// ; vim:ts=8:expandtab:filetype=z8a:syntax=z8a:
// -- end: inlin.asm
// ;--------------------------------
// ; $00B7 BREAKX
// ; Tests status of CTRL-STOP.
// ; This routine reads the keyboard status from the hardware, so its result
// ; will be accurate even if interrupts have been disabled for a while.
// ; Output: CF set if CTRL-STOP is pressed
// ; Changes: AF
proc breakx() {
A -in GIO_REGS & 0xf0 | 0x07
-out GIO_REGS
A -in KBD_STAT & 0x10 // ; check STOP, also resets CF
return-if NZ? // ; some programs like to return with $10
A -in GIO_REGS & 0xf0 | 0x06
-out GIO_REGS
A -in KBD_STAT & 0x02 // ; check CTRL, also resets CF
return-if NZ?
SCF
return
}
// ;--------------------------------
// ; $00BA ISCNTC
// ; Function: Test status of STOP or CTRL-STOP; if BASIC is in a ROM (see BASROM),
// ; then check for STOP or CTRL-STOP is not done. Otherways:
// ; INTLFLG: 0 => no action
// ; INTLFLG: 3 => CTRL-STOP pressed => break program, if "STOP-interrupts not on"??
// ; INTLFLG: 4 => STOP pressed => wait in ISCNTC till stop pressed again
// ; Input: INTFLG, BASROM
// ; Registers: AF
// ; NOTE: this implementation is still a stub!
proc iscntc() {
HL -push
AF -push
HL <- iscntc_text
print_debug()
AF -pop
HL -pop
return
data iscntc_text = byte [ /*local*/
"ISCNTC" 0
]
}
// ;--------------------------------
// ; $00BD CKCNTC
// ; Function : Same as ISCNTC. used in Basic
proc ckcntc() {
JP iscntc
}
// ;--------------------------------
// ; $00C0 BEEP
// ; Function : play a short beep, and reset sound system via GICINI
// ; Registers: All
// ; NOTE: this implementation is still a stub!
proc beep() {
// ; Note: Called by CHPUT; if you need to change more regs than AF, HL, DE, BC
// ; then update CHPUT.
HL -push
AF -push
HL <- beep_text
print_debug()
AF -pop
HL -pop
return
data beep_text = byte [ /*local*/
"BEEP" 0
]
}
// ;--------------------------------
// ; $00C6 POSIT
// ; Sets cursor position.
// ; Input: H = column
// ; L = row
// ; Changes: AF
proc posit() {
// ; Note: this works because CSRX == CSRY + 1
HL -> [CSRY]
return
}
// ;--------------------------------
// ; $00C9 FNKSB
// ; Tests whether the function key display is active (FNKFLG),
// ; if so, displays them, otherwise erases them.
// ; Input: FNKFLG (#FBCE)
// ; Changes: all
// ; NOTE: This implementation is still a stub!
proc fnksb() {
HL -push
AF -push
HL <- fnksb_text
print_debug()
AF -pop
HL -pop
return
data fnksb_text = byte [ /*local*/
"FNKSB" 0
]
}
// ;--------------------------------
// ; $00CC ERAFNK
// ; Erase function key display.
// ; Changes: all
// ; NOTE: This implementation is still a stub!
// ; TODO: call H_ERAF
proc erafnk() {
// ; call H_ERAF
HL -push
AF -push
HL <- erafnk_text
print_debug()
AF -pop
HL -pop
return
data erafnk_text = byte [ /*local*/
"ERAFNK" 0
]
}
// ;--------------------------------
// ; $00CF DSPFNK
// ; Display function keys.
// ; Changes: all
// ; NOTE: This implementation is still a stub!
// ; TODO: call H_DSPF
proc dspfnk() {
// ; call H_DSPF
HL -push
AF -push
HL <- dspfnk_text
print_debug()
AF -pop
HL -pop
return
data dspfnk_text = byte [ /*local*/
"DSPFNK" 0
]
}
// ;--------------------------------
// ; $00D2 TOTEXT
// ; Forces the screen to be in the text mode.
// ; Input: SCRMOD, OLDSCR
// ; Changes: all
proc totext() {
@[SCRMOD] -? 2
return-if C?
A <- [OLDSCR]
CALL H_TOTE
A | A
JP Z? initxt
JP init32
}
// ;--------------------------------
// ; $00E1 TAPION
// ; Reads the header block after turning the cassette motor on.
// ; Output: CF = set if failed
// ; Changes: all
// ; NOTE: This implementation is still a stub!
proc tapion() {
HL -push
AF -push
HL <- tapion_text
print_debug()
AF -pop
HL -pop
// ; TODO: not implemented -> always fail
SCF
return
data tapion_text = byte [ /*local*/
"TAPION" 0
]
}
// ;--------------------------------
// ; $00E4 TAPIN
// ; Read data from the tape.
// ; Output: A = data read
// ; Changes: all
// ; NOTE: This implementation is still a stub!
proc tapin() {
HL -push
AF -push
HL <- tapin_text
print_debug()
AF -pop
HL -pop
// ; TODO: not implemented -> always fail
SCF
return
data tapin_text = byte [ /*local*/
"TAPIN" 0
]
}
// ;--------------------------------
// ; $00E7 TAPIOF
// ; Stops reading from the tape.
// ; NOTE: This implementation is still a stub!
proc tapiof() {
HL -push
AF -push
HL <- tapiof_text
print_debug()
AF -pop
HL -pop
return
data tapiof_text = byte [ /*local*/
"TAPIOF" 0
]
}
// ;--------------------------------
// ; $00EA TAPOON
// ; Turns on the cassette motor and writes the header.
// ; Input: A = zero for short header, non-zero for long header
// ; Output: CF = set if failed
// ; Changes: all
// ; NOTE: This implementation is still a stub!
proc tapoon() {
HL -push
AF -push
HL <- tapoon_text
print_debug()
AF -pop
HL -pop
// ; TODO: not implemented -> always fail
SCF
return
data tapoon_text = byte [ /*local*/
"TAPOON" 0
]
}
// ;--------------------------------
// ; $00ED TAPOUT
// ; Writes data to the tape.
// ; Input: A = data to write
// ; Output: CF = set if failed
// ; Changes: all
// ; NOTE: This implementation is still a stub!
proc tapout() {
HL -push
AF -push
HL <- tapout_text
print_debug()
AF -pop
HL -pop
// ; TODO: not implemented -> always fail
SCF
return
data tapout_text = byte [ /*local*/
"TAPOUT" 0
]
}
// ;--------------------------------
// ; $00F0 TAPOOF
// ; Stops writing on the tape.
// ; NOTE: This implementation is still a stub!
proc tapoof() {
HL -push
AF -push
HL <- tapoof_text
print_debug()
AF -pop
HL -pop
return
data tapoof_text = byte [ /*local*/
"TAPOOF" 0
]
}
// ;--------------------------------
// ; $00F3 STMOTR
// ; Changes the cassette motor state.
// ; Input: A = action: #00 stops motor, #01 starts motor,
// ; #FF inverts current state
// ; Changes: AF
proc stmotr() {
BC -push
B <- A
A -in GIO_REGS
B ++
JR Z? stmotr_inv
A -set 4
B --
JR Z? stmotr_set
A -reset 4
B --
JR Z? stmotr_set
BC -pop
return
stmotr_inv: /*local*/
A ^ 16
stmotr_set: /*local*/
A -out GIO_REGS
BC -pop
return
}
// ;--------------------------------
// ; $0090 GICINI Initialize Sound IC
// ; Function : Initialises PSG and sets initial value for the PLAY statement
// ; Registers: All
proc gicini() {
E <- 0x00
A <- 0x08
wrtpsg()
A ++
wrtpsg()
A ++
wrtpsg()
A ++
E <- 0xb8
A <- 0x07
wrtpsg()
return
}
// ;--------------------------------
// ; $0093 WRTPSG
// ; Function : Writes data to PSG-register
// ; Input : A - PSG register number
// ; E - data write
proc wrtpsg() {
DI
A -out PSG_REGS
AF -push
@E -out PSG_DATA
EI
AF -pop
return
}
// ;--------------------------------
// ; $0096 RDPSG
// ; Function : Reads value from PSG-register
// ; Input : A - PSG-register read
// ; Output : A - value read
proc rdpsg() {
A -out PSG_REGS -in PSG_STAT
return
}
// ;--------------------------------
// ; $0135 CHGSND
// ; Write to the 1-bit sound port.
// ; Input: A = zero to set sound state to 0, non-zero to set sound state to 1
// ; Changes: AF
proc chgsnd() {
A | A <- 0x0e // ; $0E = command to reset bit 7
JR Z? chgsnd_write
A ++ // ; $0F = command to set bit 7
chgsnd_write: /*local*/
A -out PPI_REGS // ; set/reset bit of port C
return
}
// ;--------------------------------
// ; $0138 RSLREG
// ; Function : Reads the primary slot register
// ; Output : A - for the value which was read
// ; 33221100
// ; ||||||- Pagina 0 (#0000-#3FFF)
// ; ||||--- Pagina 1 (#4000-#7FFF)
// ; ||----- Pagina 2 (#8000-#BFFF)
// ; ------- Pagina 3 (#C000-#FFFF)
// ; Registers: A
proc rslreg() {
A -in PSL_STAT
return
}
// ;--------------------------------
// ; $013B WSLREG
// ; Function : Writes value to the primary slot register
// ; Input : A - value value to (see RSLREG)
proc wslreg() {
A -out PSL_STAT
return
}
// ;--------------------------------
// ; $013E RDVDP
// ; Function : Reads VDP status register
// ; Output : A - Value which was read
// ; Registers: A
proc rdvdp() {
A -in VDP_STAT
return
}
// ;--------------------------------
// ;0141h SNSMAT
// ; Function : Returns the value of the specified line from the keyboard matrix
// ; Input : A - for the specified line
// ; Output : A - for data (the bit corresponding to the pressed key will be 0)
// ; Registers: AF
proc snsmat() {
DI
BC -push
C <- A
A -in GIO_REGS & 0xf0 | C
-out GIO_REGS
A -in KBD_STAT
BC -pop
EI
return
}
// ;--------------------------------
// ; $0144 PHYDIO
// ; Executes I/O for mass-storage media like diskettes.
// ; All this routine does is call H_PHYD, which should be installed by the main
// ; disk ROM.
// ; Input: B = number of sectors to save/load
// ; C = media ID of the disk
// ; DE = begin sector
// ; HL = begin address in memory
// ; Changes: all
// ; Remark: Before the call is called, the Z-flag must be reset, and the
// ; execution address which was in HL must be at the last stack address
proc phydio() {
CALL H_PHYD
return
}
// ;--------------------------------
// ; $0147 FORMAT
// ; Initialises mass-storage media like formatting of diskettes.
// ; All this routine does is call H_FORM, which should be installed by the main
// ; disk ROM.
// ; Changes: all
proc format() {
CALL H_FORM
return
}
// ;--------------------------------
// ; $014A ISFLIO
// ; Function : Tests if I/O to device is taking place
// ; Output : A - #00 if not taking place
// ; not #00 if taking place
// ; Registers: AF
// ; TODO: call H_ISFL
proc isflio() {
// ; call H_ISFL
@[PTRFIL] & A // ; adjust flags
return
}
// ;--------------------------------
// ; $00D5 GTSTCK
// ; Function : Returns the joystick status
// ; Input : A - Joystick number to test (0 = cursors, 1 = port 1, 2 = port 2)
// ; Output : A - Direction,D = $00(when A=0)
// ; Registers: All
proc gtstck() {
BC -push
A -? 0x00
JR NZ? joy_stc1
A <- 0x08
snsmat()
A >* 4 -not & 0x0f // ; 0000RDUL
HL -push <- joypos_kbd_tbl
D <- 0
E <- A
HL + DE
A <- [HL]
HL -pop
BC -pop
A & A
return
joy_stc1: /*local*/
// ;PSG reg 15h
// ;0J001111
// ;PSG reg 14h
// ;00BARLDU
HL -push
DE -push
E <- 0x00
A --
JR Z? sel_stc1
E -set 6 // ; select stick 2
sel_stc1: /*local*/
A <- 0x0f
DI
rdpsg()
EI
A & 0xbf | E -> E
A <- 0x0f
wrtpsg()
A <- 0x0e
DI
rdpsg()
EI
A -not & 0x0f // ; 0000RLDU
HL <- joypos_joy_tbl
B <- 0
C <- A
HL + BC
A <- [HL]
DE -pop
HL -pop
BC -pop
A & A
return
}
proc joy_end() { /*unused*/
A <- 0x00
BC -pop
A & A
return
}
data joypos_joy_tbl = byte [
// ; 0 1 2 3 4 5 6 7
0x00 0x01 0x05 0x00 0x07 0x08 0x06 0x07
// ; 8 9 A B C D E F
0x03 0x02 0x04 0x03 0x00 0x01 0x05 0x00
]
data joypos_kbd_tbl = byte [
// ; 0 1 2 3 4 5 6 7
0x00 0x07 0x01 0x08 0x05 0x06 0x00 0x07
// ; 8 9 A B C D E F
0x03 0x00 0x02 0x01 0x04 0x05 0x03 0x00
]
// ;--------------------------------
// ; $00D8 GTTRIG
// ; Function : Returns current trigger status
// ; Input : A - trigger button to test
// ; 0 = spacebar(included A-1 = minus)
// ; 1 = port 1, button A
// ; 2 = port 2, button A
// ; 3 = port 1, button B
// ; 4 = port 2, button B
// ; Output : A - #00 trigger button not pressed
// ; #FF trigger button pressed
// ; Note : Some programs rely on ZF to be set according to the value in A.
// ; Registers: All
proc gttrig() {
A -? 5
JR NC? gttrig_space // ; if value of A is above 5,go space routine
A | A
JR NZ? joy_trig
gttrig_space: /*local*/
// ; Keyboard (spacebar)
A <- 0x08
snsmat() // ; bit0 = 0 -> space pressed
A | 0xfe // ; FE -> pressed, FF -> not pressed
++ // ; FF -> pressed, 00 -> not pressed
return
// ; Joystick triggers
joy_trig: /*local*/
DI
A --
DE -push
E <- 0x03 // ; enable trig A+B of stick 1
B <- A
A & 0x01
JR Z? sel_trig1
E <- 0x4c // ; enable trig A+B of stick 2 and select stick 2
sel_trig1: /*local*/
A <- 0x0f
rdpsg()
A & 0xbf | E -> E
A <- 0x0f
wrtpsg()
A <- B
B <- 0x10
A & 0x02
JR Z? istrg_a
B <- 0x20
istrg_a: /*local*/
A <- 0x0e
DI
rdpsg()
EI
DE -pop
A & B
JR Z? trig_on
JR trig_off
trig_on: /*local*/
A <- 0xff
return
trig_off: /*local*/
A ^ A
return
}
// ;--------------------------------
// ; $00DB GTPAD
// ; Function : Returns current touch pad status
// ; Input : A - Touchpad number to test
// ; Output : A - Value
// ; Registers: All
// ; NOTE : This implementation is still a stub!
proc gtpad() {
HL -push
AF -push
HL <- gtpad_text
print_debug()
AF -pop
HL -pop
A ^ A // ; haywire
return
data gtpad_text = byte [ /*local*/
"GTPAD" 0
]
}
// ;--------------------------------
// ; $00DE GTPDL
// ; Function : Returns currenct value of paddle
// ; Input : A - Paddle number
// ; Output : A - Value
// ; Registers: All
// ; NOTE : This implementation is still a stub!
proc gtpdl() {
HL -push
AF -push
HL <- gtpdl_text
print_debug()
AF -pop
HL -pop
return
data gtpdl_text = byte [ /*local*/
"GTPDL" 0
]
}
// ;--------------------------------
// ; $00F6 LFTQ
// ; Give the number of bytes left in a queue.
// ; In: A = queue number
// ; Out: HL = number of bytes left
// ; Changes: AF, BC, HL
proc lftq() {
calc_queue_address()
B <- [HL] // ; B = put position
++
HL ++
A <- [HL] // ; A = get position
- B // ; (getpos - putpos) & size
HL ++ ++
A & [HL] -> L
H <- 0x00 // ; Queues are smaller than 256 bytes.
return
}
// ;--------------------------------
// ; $00F9 PUTQ
// ; Put a byte in a queue.
// ; In: A = queue number
// ; E = data
// ; Out: ZF = set if the queue is full
// ; Changes: AF, BC, HL
proc putq() {
// ; Check whether the queue is full.
calc_queue_address()
@[HL] ++ -> B // ; B = put position + 1
HL ++
A - [HL]
return-if Z?
// ; Save the new put position.
A <- B
HL ++ ++ -push
A & [HL] // ; (putpos + 1) & size
HL -- -- --
A -> [HL]
// ; Put the data byte in the queue.
HL -pop ++
A <- [HL] // ; Get the buffer address.
HL ++
H <- [HL]
L <- A
B -- // ; Add putpos.
-> C
B <- 0
HL + BC
E -> [HL]
A | 1
return
}
// ; Calculate the address to the start of queue control block.
// ; A = queue number
proc calc_queue_address() {
HL <- [QUEUES] // ; See QUETAB in systemvars.asm.
B <- A // ; (queue number * 6)
A <* 2 + B + B -> C
B <- 0
HL + BC
return
}
// ;--------------------------------
// ; $0132 CHGCAP
// ; Function : Alternates the CAP lamp status
// ; Input : A - #00 is lamp on
// ; not #00 is lamp off
// ; Registers: AF
proc chgcap() {
A | A -in GIO_REGS -reset 6
JR NZ? chgcap_on
A -set 6
chgcap_on: /*local*/
A -out GIO_REGS
return
}
// ;--------------------------------
// ; $014D OUTDLP
// ; Function : Printer output
// ; Input : A - code to print
// ; Registers: F
// ; Remark : Differences with LPTOUT:
// ; 1. TAB is expanded to spaces
// ; 2. For non-MSX printers, Hiragana is transformed to katakana
// ; and graphic characters are transformed to 1-byte characters
// ; 3. If failed, device I/O error occurs
// ; TODO : This implementation is still a stub!
proc outdlp() {
HL -push
AF -push
HL <- outdlp_text
print_debug()
AF -pop
HL -pop
return
data outdlp_text = byte [ /*local*/
"OUTDLP" 0
]
}
// ;--------------------------------
// ; $0150 GETVCP
// ; Returns pointer to a variable at offset 2 in a voice structure.
// ; TODO: find out the purpose of this variable.
// ; Address : #0150
// ; Function : Returns pointer to play queue
// ; Input : A - Channel number
// ; Output : HL - Pointer
// ; Registers: AF
// ; Remark : Only used to play music in background
proc getvcp() {
L <- 2
JR getvc2_a
}
// ;--------------------------------
// ; $0153 GETVC2
// ; Returns pointer to a given variable in a voice structure.
// ; Input : L - Pointer in play buffer
// ; (VOICEN) - Voice structure number
// ; Output : HL - Pointer
// ; Registers: AF
proc getvc2() {
A <- [VOICEN]
fallthrough
}
proc getvc2_a() {
DE -push
D <- 0
E <- L
HL@VCBA + DE
E <- 37 // ; Size of a structure
getvc2_loop: /*local*/
A | A
JR Z? getvc2_exit
HL + DE
A --
JR getvc2_loop
getvc2_exit: /*local*/
DE -pop
return
}
// ;--------------------------------
// ; $0156 KILBUF
// ; Empties the keyboard buffer.
// ; Changes: HL
proc kilbuf() {
HL@[GETPNT] -> [PUTPNT]
return
}
// ;--------------------------------
// ; Interrupt routine ($0038h)
// ;--------------------------------
// ; some games uses Reg.R and the routine affects the register's value.
// ; if you want to add something to the routine,please try the following first
// ;
// ; Riseout , Replicart
proc keyint() {
HL -push
DE -push
BC -push
AF -push
EXX
AF <-> AF-
HL -push
DE -push
BC -push
AF -push
IY -push
IX -push
CALL H_KEYI
A -in VDP_STAT | A -> [STATFL] // ; save status
JP P? int_end // ; exit if this is not the VDP int
CALL H_TIMI
// ; TODO: (BASIC related stuff)
// ; Check sprite collision
// ; Update INTCNT
HL@[JIFFY] ++ -> [JIFFY]
// ; TODO: MUSICF
// ; TODO: It seems unsafe to me to already allow interrupts
// ; while this one is still busy: possible interference
// ; between two interrupts and also the amount of stack
// ; space claimed is a lot.
// ;ei
// ; Riseout needs that count of RegR in the routine is not
// ; even number
// ; nop
A ^ A -> [CLIKFL]
// ; Scan the keyboard every three interrupts.
@[SCNCNT] -- -> [SCNCNT]
JR NZ? int_end
@3 -> [SCNCNT]
// ; TODO read joystick triggers and space for TRGFLG
A ^ A
gttrig()
A -not & 0x01 -> [TRGFLG]
key_in()
// ; Check whether KEYBUF is empty and if so, decrement REPCNT to
// ; see if auto-repeating should be started. The user program
// ; needs to continuously read characters to allow repetition.
HL <- [PUTPNT]
DE <- [GETPNT]
RST 0x20
JR NZ? int_end
@[REPCNT] -- -> [REPCNT]
JR NZ? int_end
HL <- OLDKEY
BC <- 0x0bff
clear_oldkey: /*local*/
C -> [HL]
HL ++
DJNZ clear_oldkey
key_in()
@1 -> [REPCNT]
int_end: /*local*/
IX -pop
IY -pop
AF -pop
BC -pop
DE -pop
HL -pop
EXX
AF <-> AF- -pop
BC -pop
DE -pop
HL -pop
EI
return
}
// ;--------------------------------
// ; 0066h NMI interrupt
proc nmi() {
CALL H_NMI
RETN
}
// ;--------------------------------
// ; Get buffer from keyboard input
proc key_in() {
A -in GIO_REGS & 0xf0 -> C
B <- 11
HL <- NEWKEY
key_in_lp: /*local*/
@C -out GIO_REGS
A -in KBD_STAT -> [HL]
HL ++
C ++
DJNZ key_in_lp
IX <- OLDKEY
DE <- NEWKEY
// ; Use plain or SHIFT version of rows 0-5?
// ; Note that while we have tables for GRAPH and CODE variants,
// ; those are not used yet by this routine.
@[(NEWKEY + 6)] >* 1
HL <- scode_tbl
JR C? scan_start
HL <- scode_tbl_shift
scan_start: /*local*/
C <- 11
key_chk_lp: /*local*/
@[DE] -? [IX 0]
CALL NZ? key_set_delay
A -not & [IX 0]
AF <-> AF- // ; Update OLDKEY.
@[DE] -> [IX 0]
AF <-> AF-
// ; TODO: Optimise scanning if no keys are pressed.
// ; That's the most common case by far.
B <- 0x08
key_bit_lp: /*local*/
A >* 1
JR C? key_store
key_bit_next: /*local*/
HL ++
DJNZ key_bit_lp
IX ++
DE ++
C --
return-if Z?
@C -? 5
JR NZ? key_chk_lp
// ; Switch to new table for rows 6-11.
// ; These rows produce the same characters regardless of which
// ; modifier keys are held.
HL <- scode_tbl_otherkeys
JR key_chk_lp
key_set_delay: /*local*/
// ; Set the auto-repeat delay.
AF -push
@5 -> [REPCNT]
AF -pop
return
key_store: /*local*/
AF -push
@C -? 0x05
JR Z? key_chk_fnk1
A -? 0x04
JR Z? key_chk_fnk2
JP key_ascii
// ; Put function string into buffer
key_chk_fnk1: /*local*/
// ; F1-F3
@B -? 0x03 // ; F1
JR NZ? key_chk_f2
A <- 0x00
JR put_key_fnk
key_chk_f2: /*local*/
A -? 0x02 // ; F2
JR NZ? key_chk_f3
A <- 0x01
JR put_key_fnk
key_chk_f3: /*local*/
A -? 0x01 // ; F3
JR NZ? key_ascii // ; return to normal process
A <- 0x02
JR put_key_fnk
key_chk_fnk2: /*local*/
// ; F4-F5
@B -? 0x08 // ; F4
JR NZ? key_chk_f5
A <- 0x03
JR put_key_fnk
key_chk_f5: /*local*/
A -? 0x07 // ; F5
JR NZ? key_ascii
A <- 0x04
JR put_key_fnk
put_key_fnk: /*local*/
HL -push
BC -push
DE -push
A <* 4
HL <- FNKSTR
D <- 0x00
E <- A
HL + DE
DE <-> HL
put_key_fnk_lp: /*local*/
@[DE] & A
JR Z? put_key_fnk_nul
DE -push
CALL key_put_into_buf
DE -pop ++
JR put_key_fnk_lp
put_key_fnk_nul: /*local*/
DE -pop
BC -pop
HL -pop
JR key_store_end2
// ; Check scan table
key_ascii: /*local*/
A <- [HL] // ; get ASCII value
& A // ; dead key?
JR Z? key_store_end2
// ; Store ASCII value in key buffer.
// ; Since a full buffer is indicated by PUTPNT == GETPNT - 1,
// ; it is always safe to store a character, but if the buffer
// ; is full, PUTPNT cannot be increased.
HL -push
CALL key_put_into_buf
HL -pop
key_store_end2: /*local*/
AF -pop
JP key_bit_next
// ;--------------------------------
key_put_into_buf: /*local*/
HL <- [PUTPNT]
A -> [HL]
// ; Note: Ashguine 2 has a bug: it puts KEYBUF at FDF0 iso FBF0
// ; in the name input routine. This writes keys in memory
// ; reserved for hooks, but since those hooks are only used
// ; by BASIC, the game doesn't suffer. When PUTPNT reaches
// ; FE18, it wraps back to FBF0.
HL ++
A <- L
// ; cp $00FF & (KEYBUF + 40)
A -? 0x18
JR NZ? key_store_nowrap
HL <- KEYBUF
key_store_nowrap: /*local*/
// ; Check whether the buffer is full.
DE -push <- [GETPNT]
RST 0x20
DE -pop
return-if Z?
HL -> [PUTPNT]
return
}
// ;--------------------------------
// ; $015C SUBROM
// ; Function : Calls a routine in SUB-ROM
// ; Input : IX - Address of routine in SUB-ROM
// ; Output : Depends on the routine
// ; Registers: Alternative registers, IY
// ; Remark : Use of EXTROM or CALSLT is more convenient.
// ; You have to use this routine like this:
// ; push ix
// ; jp subrom
// ; The purpose is unclear
proc subrom() { /*unused*/
extrom()
IX -pop
return
}
// ;--------------------------------
// ; $015F EXTROM
// ; Function : Calls a routine in SUB-ROM. Most common way
// ; Input : IX - Address of routine in SUB-ROM
// ; Output : Depends on the routine
// ; Registers: Alternative registers, IY
// ; Remark : Use: LD IX,address
// ; CALL EXTROM
proc extrom() {
// ; EXTROM needs to save alternative registers
// ; and when call with certain status, returns with EI
AF <-> AF-
EXX
AF -push
BC -push
DE -push
HL -push
A <- I
AF -push
EXX
IY -push
A <- [EXBRSA]
AF -push
IY -pop // ; IYH = slot ID
AF <-> AF-
calslt() // ; Perform inter-slot call.
IY -pop
AF <-> AF-
EXX
AF -pop
JP PO? extrom_skip_ei
EI
extrom_skip_ei: /*local*/
HL -pop
DE -pop
BC -pop
AF -pop
EXX
AF <-> AF-
return
}
// ;------------------------------------
proc hang_up_mode() {
JR __PC__
}
// ;------------------------------------
// ; Called if the stack underflows.
proc stack_error() { /*unused*/
CALL H_STKE
DE <- str_stack_error
JP print_error
}
// ;------------------------------------
// ; $0159 CALBAS
// ; Function : Executes inter-slot call to the routine in BASIC interpreter
// ; Input : IX - for the calling address
// ; Output : Depends on the called routine
// ; Registers: Depends on the called routine
proc calbas() {
HL -push
AF -push
HL <- calbas_text
print_debug()
AF -pop
HL -pop
DE <- str_no_basic_intr
JP print_error
data calbas_text = byte [ /*local*/
"CALBAS" 0
]
}
// ;------------------------------------
// ;Display error
// ;in DE= message address
proc print_error() {
A -in VDP_STAT // ; reset Latch
HL <- vdp_bios
B <- 0x0c
C <- VDP_ADDR
OTIR
BC <- 0x0800
lp_clearmem: /*local*/
A ^ A -out VDP_DATA
BC --
@B | C
JR NZ? lp_clearmem
HL <- B_Font
BC <- 0x0800
lp_fontset: /*local*/
@[HL] -out VDP_DATA
HL ++
BC --
@B | C
JR NZ? lp_fontset
// ;set cursor to (0,0)
@0x00 -out VDP_ADDR
@0x40 -out VDP_ADDR
HL <- str_error_prompt
A <- [HL]
lp_errprn: /*local*/
A -out VDP_DATA
HL ++
@[HL] & A
JR NZ? lp_errprn
A <- [DE]
lp_strprn: /*local*/
A -out VDP_DATA
DE ++
@[DE] & A
JR NZ? lp_strprn
JP hang_up_mode
org> 0x1bbf
}
// -- begin: font.asm
// ; Font data for C-BIOS.
// ;
// ; Copyright (c) 2010 Manuel Bilderbeek. All rights reserved.
// ;
// ; Redistribution and use in source and binary forms, with or without
// ; modification, are permitted provided that the following conditions
// ; are met:
// ; 1. Redistributions of source code must retain the above copyright
// ; notice, this list of conditions and the following disclaimer.
// ; 2. Redistributions in binary form must reproduce the above copyright
// ; notice, this list of conditions and the following disclaimer in the
// ; documentation and/or other materials provided with the distribution.
// ;
// ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
B_Font:
// -- begin: font_jp.asm
data byte [
// ; JP version font designed by BouKiCHi.
// ;
// ; Copyright (c) 2002-2005 BouKiCHi. All rights reserved.
// ;
// ; Redistribution and use in source and binary forms, with or without
// ; modification, are permitted provided that the following conditions
// ; are met:
// ; 1. Redistributions of source code must retain the above copyright
// ; notice, this list of conditions and the following disclaimer.
// ; 2. Redistributions in binary form must reproduce the above copyright
// ; notice, this list of conditions and the following disclaimer in the
// ; documentation and/or other materials provided with the distribution.
// ;
// ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ; Japanese Localized font
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 // ;1
0x00 0x7c 0x44 0x7c 0x44 0x7c 0x44 0x8c // ;2
0x00 0x20 0xa4 0xa4 0x20 0x30 0x48 0x84 // ;3
0x00 0x12 0x14 0xf8 0x38 0x54 0x92 0x10 // ;4
0x00 0x10 0x7c 0x10 0x38 0x54 0x92 0x10 // ;5
0x00 0x38 0x54 0xba 0x10 0x38 0x54 0xfe // ;6
0x00 0x10 0x10 0x7c 0x10 0x10 0x10 0xfe // ;7
0x00 0x7c 0x44 0x44 0x7c 0x44 0x44 0x7c // ;8
0x00 0x40 0x7c 0x90 0x7c 0x50 0xfc 0x10 // ;9
0x00 0xfc 0xa4 0xa4 0xfc 0x84 0x84 0x84 // ;10
0x00 0x04 0xee 0xa4 0xfe 0xac 0xe4 0x0c // ;11
0x00 0x28 0x44 0x82 0x7c 0x24 0x44 0x48 // ;12
0x00 0x24 0xce 0x55 0xec 0x62 0xd2 0x44 // ;13
0x00 0x7c 0x20 0x7c 0x44 0x7c 0x44 0x7c // ;14
0x00 0x1c 0x70 0x10 0xfe 0x10 0x10 0x10 // ;15
0x00 0xfc 0x40 0x40 0x7c 0x44 0x84 0x88 // ;16
0x00 0x00 0x7c 0x28 0x28 0x48 0x48 0x8c // ;17
0x10 0x10 0x10 0x10 0xff 0x00 0x00 0x00 // ;18
0x00 0x00 0x00 0x00 0xff 0x10 0x10 0x10 // ;19
0x10 0x10 0x10 0x10 0xf0 0x10 0x10 0x10 // ;20
0x10 0x10 0x10 0x10 0x1f 0x10 0x10 0x10 // ;21
0x10 0x10 0x10 0x10 0xff 0x10 0x10 0x10 // ;22
0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 // ;23
0x00 0x00 0x00 0x00 0xff 0x00 0x00 0x00 // ;24
0x00 0x00 0x00 0x00 0x1f 0x10 0x10 0x10 // ;25
0x00 0x00 0x00 0x00 0xf0 0x10 0x10 0x10 // ;26
0x10 0x10 0x10 0x10 0x1f 0x00 0x00 0x00 // ;27
0x10 0x10 0x10 0x10 0xf0 0x00 0x00 0x00 // ;28
0x81 0x42 0x24 0x18 0x18 0x24 0x42 0x81 // ;29
0x00 0x10 0x7c 0x10 0x10 0x28 0x48 0x84 // ;30
0x00 0x10 0x7c 0x54 0x7c 0x10 0x10 0x10 // ;31
0x00 0x10 0x10 0x54 0x54 0x94 0x10 0x30 // ;32
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 // ;33
0x00 0x18 0x18 0x18 0x18 0x18 0x00 0x18 // ;34
0x00 0x6c 0x6c 0x24 0x00 0x00 0x00 0x00 // ;35
0x00 0x24 0x7e 0x24 0x7e 0x24 0x24 0x00 // ;36
0x14 0x3e 0x54 0x54 0x3e 0x15 0x15 0x3e // ;37
0x00 0x22 0x54 0x28 0x12 0x25 0x42 0x00 // ;38
0x38 0x44 0x44 0x28 0x32 0x4a 0x7c 0x00 // ;39
0x00 0x60 0x60 0x20 0x00 0x00 0x00 0x00 // ;40
0x00 0x08 0x10 0x10 0x10 0x10 0x08 0x00 // ;41
0x00 0x10 0x08 0x08 0x08 0x08 0x10 0x00 // ;42
0x00 0x10 0x54 0x38 0x10 0x38 0x54 0x00 // ;43
0x00 0x00 0x10 0x10 0x7c 0x10 0x10 0x00 // ;44
0x00 0x00 0x00 0x00 0x60 0x60 0x20 0x00 // ;45
0x00 0x00 0x00 0x7e 0x00 0x00 0x00 0x00 // ;46
0x00 0x00 0x00 0x00 0x00 0x60 0x60 0x00 // ;47
0x00 0x02 0x04 0x08 0x10 0x20 0x40 0x00 // ;48
0x00 0x38 0x4c 0x54 0x54 0x64 0x38 0x00 // ;49
0x00 0x10 0x30 0x10 0x10 0x10 0x38 0x00 // ;50
0x00 0x38 0x44 0x04 0x38 0x40 0x7c 0x00 // ;51
0x00 0x78 0x04 0x38 0x04 0x04 0x78 0x00 // ;52
0x00 0x44 0x44 0x44 0x7c 0x04 0x04 0x00 // ;53
0x00 0x7c 0x40 0x78 0x04 0x04 0x78 0x00 // ;54
0x00 0x38 0x40 0x78 0x44 0x44 0x38 0x00 // ;55
0x00 0x7c 0x44 0x08 0x08 0x10 0x10 0x00 // ;56
0x00 0x38 0x44 0x38 0x44 0x44 0x38 0x00 // ;57
0x00 0x38 0x44 0x44 0x3c 0x04 0x38 0x00 // ;58
0x00 0x18 0x18 0x00 0x00 0x18 0x18 0x00 // ;59
0x00 0x18 0x18 0x00 0x00 0x18 0x18 0x08 // ;60
0x00 0x08 0x10 0x20 0x40 0x20 0x10 0x08 // ;61
0x00 0x00 0x7c 0x00 0x7c 0x00 0x00 0x00 // ;62
0x00 0x20 0x10 0x08 0x04 0x08 0x10 0x20 // ;63
0x00 0x38 0x44 0x04 0x18 0x10 0x00 0x10 // ;64
0x00 0x3c 0x5a 0x6a 0x5a 0x46 0x3c 0x00 // ;65
0x00 0x10 0x28 0x28 0x7c 0x44 0x44 0x00 // ;66
0x00 0x78 0x44 0x78 0x44 0x44 0x78 0x00 // ;67
0x00 0x38 0x44 0x40 0x40 0x44 0x38 0x00 // ;68
0x00 0x78 0x44 0x44 0x44 0x44 0x78 0x00 // ;69
0x00 0x7c 0x40 0x7c 0x40 0x40 0x7c 0x00 // ;70
0x00 0x7c 0x40 0x40 0x78 0x40 0x40 0x00 // ;71
0x00 0x38 0x44 0x40 0x4e 0x44 0x38 0x00 // ;72
0x00 0x44 0x44 0x7c 0x44 0x44 0x44 0x00 // ;73
0x00 0x38 0x10 0x10 0x10 0x10 0x38 0x00 // ;74
0x00 0x1c 0x08 0x08 0x08 0x48 0x30 0x00 // ;75
0x00 0x44 0x48 0x50 0x68 0x44 0x44 0x00 // ;76
0x00 0x40 0x40 0x40 0x40 0x40 0x7c 0x00 // ;77
0x00 0x44 0x6c 0x54 0x44 0x44 0x44 0x00 // ;78
0x00 0x44 0x64 0x54 0x54 0x4c 0x44 0x00 // ;79
0x00 0x38 0x44 0x44 0x44 0x44 0x38 0x00 // ;80
0x00 0x78 0x44 0x44 0x78 0x40 0x40 0x00 // ;81
0x00 0x38 0x44 0x44 0x54 0x4c 0x3c 0x06 // ;82
0x00 0x78 0x44 0x44 0x78 0x44 0x44 0x00 // ;83
0x00 0x3c 0x40 0x38 0x04 0x44 0x38 0x00 // ;84
0x00 0x7c 0x10 0x10 0x10 0x10 0x10 0x00 // ;85
0x00 0x44 0x44 0x44 0x44 0x44 0x38 0x00 // ;86
0x00 0x44 0x44 0x28 0x28 0x10 0x10 0x00 // ;87
0x00 0x54 0x54 0x54 0x54 0x28 0x28 0x00 // ;88
0x00 0x44 0x28 0x10 0x10 0x28 0x44 0x00 // ;89
0x00 0x44 0x44 0x28 0x10 0x10 0x10 0x00 // ;90
0x00 0x7c 0x04 0x08 0x10 0x20 0x7c 0x00 // ;91
0x00 0x38 0x20 0x20 0x20 0x20 0x38 0x00 // ;92
0x00 0x44 0x28 0x7c 0x10 0x7c 0x10 0x00 // ;93
0x00 0x38 0x08 0x08 0x08 0x08 0x38 0x00 // ;94
0x00 0x10 0x28 0x44 0x00 0x00 0x00 0x00 // ;95
0x00 0x00 0x00 0x00 0x00 0x00 0x7c 0x00 // ;96
0x00 0x30 0x30 0x10 0x00 0x00 0x00 0x00 // ;97
0x00 0x00 0x38 0x04 0x3c 0x44 0x3c 0x00 // ;98
0x00 0x40 0x40 0x78 0x44 0x44 0x78 0x00 // ;99
0x00 0x00 0x38 0x44 0x40 0x44 0x38 0x00 // ;100
0x00 0x04 0x04 0x3c 0x44 0x44 0x3c 0x00 // ;101
0x00 0x00 0x38 0x44 0x7c 0x40 0x3c 0x00 // ;102
0x00 0x08 0x10 0x38 0x10 0x10 0x10 0x00 // ;103
0x00 0x00 0x3c 0x44 0x3c 0x44 0x38 0x00 // ;104
0x00 0x40 0x40 0x78 0x44 0x44 0x44 0x00 // ;105
0x00 0x10 0x00 0x30 0x10 0x10 0x38 0x00 // ;106
0x00 0x10 0x00 0x10 0x10 0x10 0x60 0x00 // ;107
0x00 0x20 0x24 0x28 0x30 0x28 0x24 0x00 // ;108
0x00 0x10 0x10 0x10 0x10 0x10 0x10 0x00 // ;109
0x00 0x00 0x78 0x54 0x54 0x54 0x54 0x00 // ;110
0x00 0x00 0x78 0x44 0x44 0x44 0x44 0x00 // ;111
0x00 0x00 0x38 0x44 0x44 0x44 0x38 0x00 // ;112
0x00 0x00 0x78 0x44 0x78 0x40 0x40 0x00 // ;113
0x00 0x04 0x3c 0x44 0x3c 0x04 0x04 0x00 // ;114
0x00 0x00 0x5c 0x60 0x40 0x40 0x40 0x00 // ;115
0x00 0x00 0x3c 0x40 0x38 0x04 0x78 0x00 // ;116
0x00 0x20 0x78 0x20 0x20 0x20 0x18 0x00 // ;117
0x00 0x00 0x48 0x48 0x48 0x48 0x34 0x00 // ;118
0x00 0x00 0x44 0x44 0x44 0x28 0x10 0x00 // ;119
0x00 0x00 0x54 0x54 0x54 0x54 0x28 0x00 // ;120
0x00 0x00 0x44 0x28 0x10 0x28 0x44 0x00 // ;121
0x00 0x00 0x44 0x28 0x10 0x10 0x20 0x00 // ;122
0x00 0x00 0x7c 0x08 0x10 0x20 0x7c 0x00 // ;123
0x00 0x08 0x10 0x10 0x20 0x10 0x10 0x08 // ;124
0x00 0x10 0x10 0x10 0x10 0x10 0x10 0x00 // ;125
0x00 0x10 0x08 0x08 0x04 0x08 0x08 0x10 // ;126
0x00 0x32 0x4c 0x00 0x00 0x00 0x00 0x00 // ;127
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 // ;128
0x00 0x18 0x3c 0x7e 0x7e 0x18 0x3c 0x00 // ;129
0x00 0x24 0x7e 0x7e 0x7e 0x3c 0x18 0x00 // ;130
0x00 0x18 0x18 0x7e 0x7e 0x18 0x3c 0x00 // ;131
0x00 0x18 0x3c 0x7e 0x7e 0x3c 0x18 0x00 // ;132
0x00 0x3c 0x42 0x42 0x42 0x42 0x3c 0x00 // ;133
0x00 0x3c 0x7e 0x7e 0x7e 0x7e 0x3c 0x00 // ;134
0x00 0x10 0x7c 0x20 0x78 0x54 0x28 0x3c // ;135
0x00 0x00 0x10 0x7c 0x10 0x7c 0x5c 0x74 // ;136
0x00 0x00 0x00 0x00 0x48 0x44 0x44 0x24 // ;137
0x00 0x00 0x20 0x10 0x78 0x08 0x08 0x10 // ;138
0x00 0x00 0x20 0x10 0x78 0x08 0x30 0x48 // ;139
0x00 0x00 0x10 0x7c 0x14 0x78 0x54 0x34 // ;140
0x00 0x00 0x00 0x50 0xf8 0x54 0x48 0x20 // ;141
0x00 0x00 0x00 0x50 0x7c 0x54 0x18 0x20 // ;142
0x00 0x00 0x00 0x10 0x1c 0x30 0x58 0x34 // ;143
0x00 0x00 0x00 0x00 0x78 0x04 0x04 0x38 // ;144
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 // ;145
0x00 0x20 0xf8 0x20 0x7c 0xac 0xb4 0x74 // ;146
0x00 0x00 0x88 0x88 0x84 0x84 0xa4 0x40 // ;147
0x00 0x60 0x00 0x70 0x88 0x08 0x10 0x60 // ;148
0x00 0x60 0x10 0xf8 0x20 0x60 0x50 0x98 // ;149
0x00 0x24 0xf4 0x20 0x78 0xa4 0xa4 0x68 // ;150
0x00 0x48 0xe4 0x54 0x50 0x90 0x10 0x60 // ;151
0x00 0x40 0xf8 0x20 0xf8 0x10 0x80 0x70 // ;152
0x00 0x20 0x20 0x40 0x80 0x40 0x20 0x20 // ;153
0x00 0x88 0x88 0xbc 0x88 0x88 0x88 0x50 // ;154
0x00 0x00 0xf8 0x08 0x00 0x00 0x80 0x78 // ;155
0x00 0x20 0xf8 0x20 0x20 0x00 0x80 0x70 // ;156
0x00 0x80 0x80 0x80 0x80 0x80 0x88 0x70 // ;157
0x00 0x10 0xfc 0x30 0x50 0x30 0x10 0x60 // ;158
0x00 0x48 0xfc 0x48 0x48 0x48 0x40 0x38 // ;159
0x00 0x44 0x28 0xfc 0x30 0x40 0x40 0x38 // ;160
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 // ;161
0x00 0x00 0x00 0x00 0x08 0x14 0x08 0x00 // ;162
0x00 0x60 0x40 0x40 0x00 0x00 0x00 0x00 // ;163
0x00 0x00 0x00 0x00 0x04 0x04 0x0c 0x00 // ;164
0x00 0x00 0x00 0x00 0x10 0x08 0x08 0x00 // ;165
0x00 0x00 0x00 0x30 0x30 0x00 0x00 0x00 // ;166
0x00 0x00 0x00 0x7c 0x04 0x7c 0x04 0x38 // ;167
0x00 0x00 0x00 0x7c 0x04 0x14 0x10 0x20 // ;168
0x00 0x00 0x00 0x08 0x18 0x70 0x10 0x10 // ;169
0x00 0x00 0x00 0x10 0x7c 0x44 0x04 0x18 // ;170
0x00 0x00 0x00 0x00 0x38 0x10 0x10 0x7c // ;171
0x00 0x00 0x00 0x08 0x7c 0x18 0x28 0x48 // ;172
0x00 0x00 0x00 0x20 0x7c 0x24 0x24 0x20 // ;173
0x00 0x00 0x00 0x00 0x38 0x08 0x08 0x7c // ;174
0x00 0x00 0x00 0x7c 0x04 0x7c 0x04 0x7c // ;175
0x00 0x00 0x00 0x54 0x54 0x04 0x04 0x18 // ;176
0x00 0x00 0x00 0x40 0x3c 0x00 0x00 0x00 // ;177
0x00 0x7c 0x04 0x14 0x14 0x14 0x20 0x40 // ;178
0x00 0x04 0x08 0x18 0x30 0x50 0x10 0x10 // ;179
0x00 0x10 0x7c 0x44 0x44 0x04 0x08 0x10 // ;180
0x00 0x00 0x7c 0x10 0x10 0x10 0x10 0x7c // ;181
0x00 0x08 0x7c 0x08 0x18 0x28 0x48 0x18 // ;182
0x00 0x10 0x7c 0x14 0x24 0x24 0x44 0x08 // ;183
0x00 0x10 0x7c 0x10 0x7c 0x10 0x10 0x10 // ;184
0x00 0x20 0x3c 0x24 0x44 0x08 0x08 0x30 // ;185
0x00 0x20 0x3c 0x28 0x48 0x08 0x10 0x20 // ;186
0x00 0x00 0x7c 0x04 0x04 0x04 0x04 0x7c // ;187
0x00 0x28 0x7c 0x28 0x28 0x08 0x08 0x30 // ;188
0x00 0x64 0x04 0x64 0x04 0x04 0x08 0x70 // ;189
0x00 0x7c 0x04 0x04 0x08 0x10 0x28 0x44 // ;190
0x00 0x20 0x7c 0x24 0x20 0x20 0x20 0x1c // ;191
0x00 0x44 0x44 0x44 0x04 0x04 0x08 0x30 // ;192
0x00 0x1c 0x24 0x24 0x7c 0x04 0x08 0x10 // ;193
0x00 0x04 0x78 0x10 0x7c 0x10 0x10 0x20 // ;194
0x00 0x54 0x54 0x54 0x04 0x04 0x08 0x30 // ;195
0x00 0x38 0x00 0x7c 0x10 0x10 0x10 0x20 // ;196
0x00 0x20 0x20 0x20 0x38 0x24 0x20 0x20 // ;197
0x00 0x10 0x7c 0x10 0x10 0x10 0x10 0x20 // ;198
0x00 0x00 0x38 0x00 0x00 0x00 0x00 0x7c // ;199
0x00 0x7c 0x04 0x48 0x30 0x10 0x28 0x44 // ;200
0x00 0x10 0x7c 0x08 0x38 0x54 0x54 0x10 // ;201
0x00 0x08 0x08 0x08 0x08 0x10 0x10 0x60 // ;202
0x00 0x08 0x08 0x48 0x44 0x44 0x44 0x44 // ;203
0x00 0x40 0x78 0x40 0x40 0x40 0x40 0x3c // ;204
0x00 0x00 0x7c 0x04 0x04 0x08 0x08 0x30 // ;205
0x00 0x00 0x20 0x50 0x48 0x04 0x04 0x00 // ;206
0x00 0x10 0x7c 0x10 0x10 0x54 0x54 0x10 // ;207
0x00 0x00 0x7c 0x04 0x48 0x30 0x10 0x08 // ;208
0x00 0x60 0x1c 0x60 0x1c 0x00 0x60 0x1c // ;209
0x00 0x10 0x20 0x28 0x48 0x44 0x7c 0x04 // ;210
0x00 0x04 0x04 0x28 0x10 0x18 0x24 0x40 // ;211
0x00 0x7c 0x20 0x20 0x7c 0x20 0x20 0x1c // ;212
0x00 0x20 0xfc 0x24 0x24 0x10 0x10 0x10 // ;213
0x00 0x78 0x08 0x08 0x08 0x08 0x08 0x7c // ;214
0x00 0x7c 0x04 0x04 0x7c 0x04 0x04 0x7c // ;215
0x00 0x38 0x00 0x7c 0x04 0x04 0x04 0x38 // ;216
0x00 0x48 0x48 0x48 0x48 0x08 0x08 0x30 // ;217
0x00 0x48 0x48 0x48 0x48 0x48 0x48 0x8c // ;218
0x00 0x40 0x40 0x40 0x40 0x44 0x48 0x70 // ;219
0x00 0x7c 0x44 0x44 0x44 0x44 0x44 0x7c // ;220
0x00 0x7c 0x44 0x44 0x04 0x04 0x04 0x38 // ;221
0x00 0x64 0x04 0x04 0x04 0x08 0x08 0x70 // ;222
0x00 0x00 0x50 0x28 0x00 0x00 0x00 0x00 // ;223
0x00 0x20 0x50 0x20 0x00 0x00 0x00 0x00 // ;224
0x00 0x20 0x78 0x20 0x5c 0x40 0x40 0x9c // ;225
0x00 0x20 0x7c 0x20 0x78 0x84 0x04 0x18 // ;226
0x00 0x00 0x38 0xc4 0x04 0x04 0x04 0x78 // ;227
0x00 0x00 0x3c 0xc8 0x10 0x20 0x20 0x18 // ;228
0x00 0x84 0x48 0x30 0x20 0x40 0x40 0x3c // ;229
0x00 0x88 0x64 0x60 0x90 0x38 0x50 0x30 // ;230
0x00 0x40 0x5c 0x80 0x80 0x80 0x80 0x5c // ;231
0x00 0x80 0x44 0x78 0xd8 0xa8 0xbc 0x58 // ;232
0x00 0x48 0xd8 0x68 0x48 0xd8 0xec 0x58 // ;233
0x00 0x00 0x38 0x54 0x94 0xa4 0xa4 0x68 // ;234
0x00 0x08 0xbc 0x88 0x88 0xb8 0xac 0xb4 // ;235
0x00 0x00 0x6c 0xa8 0x48 0x48 0x48 0x30 // ;236
0x00 0x00 0x70 0x00 0x20 0x10 0x94 0xa4 // ;237
0x00 0x00 0x00 0x30 0x48 0x88 0x84 0x04 // ;238
0x00 0x00 0x9c 0x88 0xbc 0x98 0xac 0x58 // ;239
0x00 0x20 0xfc 0x20 0xfc 0x70 0xa8 0x64 // ;240
0x00 0x00 0xe0 0x28 0x78 0xac 0xa8 0x50 // ;241
0x00 0x28 0xf4 0x20 0x60 0xa4 0x64 0x38 // ;242
0x00 0x84 0x74 0x48 0xb4 0x94 0xac 0x48 // ;243
0x00 0x20 0xf8 0x40 0xfc 0x40 0x40 0x38 // ;244
0x00 0x90 0x5c 0x74 0xd4 0x48 0x40 0x20 // ;245
0x00 0x90 0xb8 0xd4 0x94 0x1c 0x10 0x20 // ;246
0x00 0x20 0x38 0x20 0x70 0xa8 0xa8 0x60 // ;247
0x00 0x40 0x20 0x80 0xb8 0xc8 0x08 0x30 // ;248
0x00 0x90 0x88 0x88 0x88 0x08 0x10 0x20 // ;249
0x00 0x78 0x10 0x30 0xc8 0x38 0x48 0x30 // ;250
0x00 0x40 0xe8 0x58 0x68 0x48 0xc8 0x4c // ;251
0x00 0x78 0x08 0x30 0x48 0x84 0x04 0x38 // ;252
0x00 0x40 0xe0 0x58 0x64 0x44 0xc4 0x58 // ;253
0x00 0x10 0x10 0x20 0x30 0x50 0x68 0xcc // ;254
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 // ;255
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 // ;256
]
// -- end: font_jp.asm
// -- end: font.asm
// ;
// ; This routine is called just after displaying the logo.
// ; This fixes the Mirai sprite garbage bug.
// ;
// -- begin: slot.asm
// ;-------------------------------------
// ; 000Ch RDSLT
// ; Reads a value from an address in another slot.
// ; Input: A = slot ID: E000SSPP
// ; HL = address to read
// ; Output: A = value read
// ; Interrupts disabled.
// ; Changes: F, C, DE
proc rdslt() {
BC -push
HL -push
AF -push
D <- A // ; init D in case call is not made
A & A // ; expanded slot?
DI
CALL M? select_subslot
AF -pop
HL -pop -push // ; HL = address
DE -push // ; D = slot ID, E = saved SSL
HL -push // ; HL = address
AF -push // ; A = slot ID
@H <* 2 & 0x03 -> L // ; L = page number
-> B
A <- 0xfc
rdsft()
E <- A // ; E = mask (shifted)
B <- L // ; B = page number
AF -pop // ; A = slot ID
A & 0x03
rdsft()
B <- A // ; B = primary slot (shifted)
A -in PSL_STAT -> D // ; D = primary slot select for restore
& E | B // ; A = primary slot select for read
HL -pop // ; HL = address
CALL rdprim
A <- E
DE -pop // ; D = slot ID, E = saved SSL
AF -push // ; A = value read
D -bit? 7 // ; expanded slot?
CALL NZ? restore_subslot
AF -pop // ; A = value read
HL -pop // ; HL = address
BC -pop
return
}
proc rdsft() {
B ++ --
return-if Z?
rdsft_lp: /*local*/
A <* 2
DJNZ rdsft_lp
return
}
// ;-------------------------------------
// ; $0014 WRSLT
// ; Writes a value to an address in another slot.
// ; Input: A = slot ID: E000SSPP
// ; HL = address to write
// ; E = value to write
// ; Output: Interrupts disabled.
// ; Changes: AF, BC, D
proc wrslt() {
HL -push
D <- A // ; D = slot ID
DE -push
A & A // ; expanded slot?
DI
CALL M? select_subslot
BC -pop // ; B = slot ID, C = data
HL -pop
DE -push // ; D = slot ID, E = saved SSL
HL -push // ; HL = address
@H <* 2 & 0x03 -> L // ; L = page number
-> B // ; B = page number
A <- 0xfc
rdsft()
E <- A // ; E = mask (shifted)
B <- L // ; B = page number
@D & 0x03 // ; A = 000000PP
rdsft()
B <- A // ; B = primary slot (shifted)
A -in PSL_STAT -> D // ; D = primary slot select for restore
& E | B // ; A = primary slot select for write
HL -pop // ; HL = address
E <- C // ; E = data
CALL wrprim
DE -pop // ; D = slot ID, E = saved SSL
HL -push // ; HL = address
D -bit? 7 // ; expanded slot?
CALL NZ? restore_subslot
HL -pop
return
}
// ;-------------------------------------
// ; $001C CALSLT
// ; Function : Executes inter-slot call.
// ; Input : IY - High byte with input for A in RDSLT
// ; IX - The address that will be called
// ; Remark : Variables can never be given in alternative registers
// ; of the Z-80 or IX and IY
proc calslt() {
AF <-> AF-
EXX
// ; Select secondary slot of target:
// ; Note: This approach fails if target is in page 0 of slot 0.1, 0.2 or 0.3.
// ; TODO: Put slot 0 specific routine in page 3, on the stack if necessary.
DI
IY -push
AF -pop // ; A = slot ID: E000SSPP
IX -push
HL -pop // ; HL = address to call
D <- A // ; init D in case call is not made
A & A // ; expanded slot?
CALL M? select_subslot
DE -push // ; D = slot ID, E = saved SSL
// ; Calculate primary slot select value:
A <- D // ; A = slot ID: E000SSPP
& 0x03 -> B // ; B = primary slot
C <- 0xfc // ; C = mask
// ; Calculate page that contains call address.
IX -push
AF -pop // ; A = high byte call address
A <* 2 & 0x03 // ; A = page
// ; Shift B and C page*2 positions to the left.
A + A
JR Z? calslt_sh2
calslt_sh1: /*local*/
B <* 1
C <* 1
A --
JR NZ? calslt_sh1
calslt_sh2: /*local*/
// ; Select primary slot of target and perform call:
HL@calslt_restore -push
A -in PSL_STAT
AF -push
A & C // ; C = mask (shifted)
| B // ; B = primary slot (shifted)
EXX
JP clprim
calslt_restore: /*local*/
AF <-> AF-
EXX
// ; Restore secondary slot:
DI
DE -pop // ; D = slot ID, E = saved SSL
D -bit? 7 // ; expanded slot?
CALL NZ? restore_subslot
// ; Done:
AF <-> AF-
EXX
return
}
// ;-------------------------------------
// ; $0024 ENASLT
// ; Selects a slot in the page specified by an address.
// ; Input: A = slot ID: ExxxSSPP
// ; E = expanded flag
// ; SS = secondary slot number (only if expanded)
// ; PP = primary slot number
// ; HL = address inside the page to change
// ; Output: Interrupts disabled.
// ; Changes: AF, BC, DE
proc enaslt() {
// ; A=(A >> 6)&0x3
DI
HL -push
L <- A // ; L = ExxxSSPP
A & 0x03 // ; A = 000000PP
-> B
A <- 0xab
psl_dup_lp: /*local*/
A + 0x55
B --
JP P? psl_dup_lp
D <- A // ; D = PP PP PP PP
@H <* 2 & 0x03 -> H // ; H = page number (0-3)
-> B
A <- 0xc0
page_msk_lp: /*local*/
A <* 2
B --
JP P? page_msk_lp
E <- A // ; E = page mask (00 00 00 11 << page)
A -not -> C // ; C = page mask complement
@D & E -> B // ; B = 00 00 00 PP << page
@L & A
JP P? chg_psl
// ;SSL-Change
A >* 2 & 0x03 // ; A = 000000SS
HL -push
BC -push
B <- A
A <- 0xab
ssl_dup_lp: /*local*/
A + 0x55
B --
JP P? ssl_dup_lp
A & E -> B // ; B = 00 00 00 SS << page
@D & 0xc0 -> H
A -in PSL_STAT -> L & 0xc0 | H
-out PSL_STAT
@[SSL_REGS] -not & C // ; preserve other pages
| B -> C -> [SSL_REGS]
@L -out PSL_STAT
// ; (SLTTBL + PP) <- RegC
HL <- SLTTBL
@D & 0x03 // ; A = 000000PP
+ L -> L // ; L = L + A
@H +$ 0 -> H // ; H = H + Cy
@C -> [HL]
BC -pop
HL -pop
chg_psl: /*local*/
A -in PSL_STAT & C | B
-out PSL_STAT
HL -pop
return
}
// ;--------------------------------
// ; Select subslot.
// ; Input: A = slot ID: E000SSPP
// ; HL = address which specifies page to select
// ; (actually, only the highest 2 bits of H are relevant)
// ; Output: D = slot ID (same as input)
// ; E = original value of secondary slot select register
// ; SLTTBL[slot] = new value of secondary slot select register
// ; Changes: AF, HL, BC
// ; Note: Interrupts must be disabled before calling this routine.
proc select_subslot() {
// ; Select primary slot of target in page 3.
// ; Note: Stack is unavailable until primary slot is restored.
D <- A // ; D = E000SSPP
A >* 2 -> E // ; E = PPE000SS
& 0xc0 -> L // ; L = PP000000
A -in PSL_STAT -> C // ; C = saved PSL
& 0x3f | L -out PSL_STAT
// ; Shift mask and subslot according to page.
A <- E // ; A = PPE000SS
& 0x03 -> L // ; L = subslot
A <- H // ; A = high byte of address
H <- 0x03 // ; H = mask
JR select_subslot_next
select_subslot_lp: /*local*/
HL + HL // ; Shift 2 bits to the left.
+ HL
select_subslot_next: /*local*/
A - 0x40 // ; Subtract 1 page.
JR NC? select_subslot_lp
@H -not -> H
// ; Select secondary slot of target.
@[SSL_REGS] -not -> E // ; E = saved SSL
& H // ; H = mask (shifted)
| L // ; L = subslot (shifted)
-> [SSL_REGS] -> L // ; L = value written to SSL_REGS
// ; Restore original primary slot in page 3.
@C -out PSL_STAT
// ; Update SLTTBL.
@D & 0x03 // ; A = 000000SS
-> C
B <- 0
A <- L // ; A = value written to SSL_REGS
HL@SLTTBL + BC
A -> [HL]
return
}
// ;--------------------------------
// ; Restore subslot, companion routine to select_subslot.
// ; Input: D = slot ID: E000SSPP
// ; E = original value of secondary slot select register
// ; Output: SLTTBL[slot] = original value of secondary slot select register
// ; Changes: AF, HL, BC
// ; Note: Interrupts must be disabled before calling this routine.
proc restore_subslot() {
// ; Select primary slot of target in page 3.
// ; Note: Stack is unavailable until primary slot is restored.
@D >* 2 & 0xc0 -> B // ; B = PP000000
A -in PSL_STAT -> C // ; C = saved PSL
& 0x3f | B -out PSL_STAT
// ; Restore secondary slot.
@E -> [SSL_REGS]
// ; Restore original primary slot in page 3.
@C -out PSL_STAT
// ; Update SLTTBL.
@D & 0x03 // ; A = 000000SS
-> C
B <- 0
HL@SLTTBL + BC
E -> [HL]
return
}
// ;--------------------------------
proc m_rdprim() {
A -out PSL_STAT
E <- [HL]
JR m_wrprm1
}
proc m_wrprim() {
A -out PSL_STAT
E -> [HL]
fallthrough
}
proc m_wrprm1() {
@D -out PSL_STAT
return
}
proc m_clprim() {
A -out PSL_STAT
AF <-> AF-
CALL cl_jp
AF <-> AF- -pop
A -out PSL_STAT
AF <-> AF-
return
}
proc m_cl_jp() {
JP [IX]
}
m_prim_end:
NOP
const rdprim = 0xf380
const wrprim = rdprim + (m_wrprim - m_rdprim)
const clprim = rdprim + (m_clprim - m_rdprim)
const cl_jp = rdprim + (m_cl_jp - m_rdprim)
// ; vim:ts=8:expandtab:filetype=z8a:syntax=z8a:
// -- end: slot.asm
// ;---------------------------------
// ; system messages
// ;---------------------------------
str_proginfo:
// ; [01234567890123456789012345678]
// ;db "C-BIOS 1.23 cbios.sf.net"
// -- begin: ../derived/asm/version.asm
data byte ["C-BIOS 0.29 cbios.sf.net"]
// -- end: ../derived/asm/version.asm
data byte [0x0d 0x0a]
// -- begin: locale.asm
data byte [
"Character set: "
"JP"
0x0d 0x0a
"Interrupt frequency: "
"6"
"0Hz"
]
// ; the text fits exactly a line for non-MSX1 VDP
data byte [
0x0d 0x0a
"Keyboard type: "
"JP"
0x0d 0x0a
// ;BASIC type is not very interesting without BASIC
// ;db "BASIC type: "
// ;IF LOCALE_BASIC = LOCAL_BASIC_US
// ; db "US"
// ;ENDIF
// ;IF LOCALE_BASIC = LOCAL_BASIC_JP
// ; db "JP"
// ;ENDIF
0x0d 0x0a
]
// -- end: locale.asm
data byte [0x0d 0x0a 0x0d 0x0a 0x00]
const str_proginfo_length = __PC__ - str_proginfo
data str_slot = byte [
// ; [01234567890123456789012345678]
"Init ROM in slot: " 0x00
]
data str_basic = byte [
// ; [01234567890123456789012345678]
"Cannot execute a BASIC ROM." 0x0d 0x0a 0x00
]
// ;-------------------------------------
// ; error messages
data str_error_prompt = byte [
"ERROR:" 0x00
]
data str_memory_err = byte [
"MEMORY NOT FOUND." 0x00
]
data str_no_basic_intr = byte [
"CALLED NON EXISTING BASIC." 0x00
]
data str_stack_error = byte [
"STACK ERROR." 0x00
]
data str_nocart = byte [
// ; [01234567890123456789012345678]
0x0d 0x0a 0x0d 0x0a
"No cartridge found." 0x0d 0x0a
0x0d 0x0a
"This version of C-BIOS can" 0x0d 0x0a
"only start cartridges." 0x0d 0x0a
"Please restart your MSX" 0x0d 0x0a
"(emulator) with a cartridge" 0x0d 0x0a
"inserted." 0x00
]
// ;-------------------------------------
// ; scan code tables
// -- begin: scancodes_jp.asm
// ; Scan code tables JIS (japanese) keybaord for C-BIOS
// ;
// ; Copyright (c) 2008 Eric Boon. All rights reserved.
// ;
// ; Redistribution and use in source and binary forms, with or without
// ; modification, are permitted provided that the following conditions
// ; are met:
// ; 1. Redistributions of source code must retain the above copyright
// ; notice, this list of conditions and the following disclaimer.
// ; 2. Redistributions in binary form must reproduce the above copyright
// ; notice, this list of conditions and the following disclaimer in the
// ; documentation and/or other materials provided with the distribution.
// ;
// ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ;
// ; -------------------------------------
// ; scan code tableS
data scode_tbl = byte [
// ; Japanese
"01234567" // ;00
"89-^" 0x5c "@[;" // ;01 ($5C = yen)
":],./_ab" // ;02
"cdefghij" // ;03
"klmnopqr" // ;04
"stuvwxyz" // ;05
]
data scode_tbl_shift = byte [
"0!" 0x22 "#$%&'" // ;00 ($22 = quote)
"()=~|`{+" // ;01
"*}<>?_AB" // ;02
"CDEFGHIJ" // ;03
"KLMNOPQR" // ;04
"STUVWXYZ" // ;05
]
data scode_tbl_graph = byte [ /*unused*/
0x0f 0x07 0x01 0x02 0x03 0x04 0x05 0x06 // ;00
0x0d 0xe0 0x17 0x00 0x09 0x00 0x84 0x82 // ;01
0x81 0x85 0x1f 0x1d 0x80 0x83 0x00 0x1b // ;02
0x1a 0x14 0x18 0x15 0x13 0x0a 0x16 0x00 // ;03
0x00 0x1e 0x0b 0x00 0x00 0x10 0x00 0x12 // ;04
0x0c 0x19 0x00 0x11 0x00 0x1c 0x08 0x00 // ;05
]
// ; TODO SHIFT + GRAPH is undefined in the red book. Same keycodes
// ; as with shift or no key entered? (all $00)
data scode_tbl_shift_graph = byte [ /*unused*/
0x0f 0x07 0x01 0x02 0x03 0x04 0x05 0x06 // ;00
0x0d 0xe0 0x17 0x00 0x09 0x00 0x84 0x82 // ;01
0x81 0x85 0x1f 0x1d 0x80 0x83 0x00 0x1b // ;02
0x1a 0x14 0x18 0x15 0x13 0x0a 0x16 0x00 // ;03
0x00 0x1e 0x0b 0x00 0x00 0x10 0x00 0x12 // ;04
0x0c 0x19 0x00 0x11 0x00 0x1c 0x08 0x00 // ;05
]
data scode_tbl_kana = byte [ /*unused*/
0xfc 0xe7 0xec 0x91 0x93 0x94 0x95 0xf4 // ;00
0xf5 0xf6 0xee 0xed 0xb0 0xde 0xdf 0xfa // ;01
0x99 0xf1 0xe8 0xf9 0xf2 0xfb 0xe1 0x9a // ;02
0x9f 0x9c 0x92 0xea 0x97 0x98 0xe6 0xef // ;03
0xe9 0xf8 0xf3 0xf0 0xf7 0x9e 0xe0 0x9d // ;04
0xe4 0x96 0xe5 0xeb 0xe3 0x9b 0xfd 0xe2 // ;05
]
data scode_tbl_caps_kana = byte [ /*unused*/
0xdc 0xc7 0xcc 0xb1 0xb3 0xb4 0xb5 0xd4 // ;00
0xd5 0xd6 0xce 0xcd 0xb0 0xde 0xdf 0xda // ;01
0xb9 0xd1 0xc8 0xd9 0xd2 0xdb 0xc1 0xba // ;02
0xbf 0xbc 0xb2 0xca 0xb7 0xb8 0xc6 0xcf // ;03
0xc9 0xd8 0xd3 0xd0 0xd7 0xbe 0xc0 0xbd // ;04
0xc4 0xb6 0xc5 0xcb 0xc3 0xbb 0xdd 0xc2 // ;05
]
data scode_tbl_shift_kana = byte [ /*unused*/
0x86 0x00 0x00 0x87 0x89 0x8a 0x8b 0x8c // ;00
0x8d 0x8e 0x00 0x00 0x00 0x00 0xa2 0x00 // ;01
0x00 0x83 0x84 0x81 0x85 0x00 0x00 0x00 // ;02
0x00 0x00 0x88 0x00 0x00 0x00 0x00 0x00 // ;03
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 // ;04
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x8f // ;05
]
data scode_tbl_shift_caps_kana = byte [ /*unused*/
0xa6 0x00 0x00 0xa7 0xa9 0xaa 0xab 0xac // ;00
0xad 0xae 0x00 0x00 0x00 0x00 0xa2 0x00 // ;01
0x00 0xa3 0xa4 0xa1 0xa5 0x00 0x00 0x00 // ;02
0x00 0x00 0xa8 0x00 0x00 0x00 0x00 0x00 // ;03
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 // ;04
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xaf // ;05
]
// ; vim:ts=8:expandtab:filetype=z8a:syntax=z8a:
// -- end: scancodes_jp.asm
// ; the last rows are not locale specific
data scode_tbl_otherkeys = byte [
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 // ;06
0x00 0x00 0x1b 0x09 0x00 0x08 0x00 0x0d // ;07
0x20 0x0c 0x00 0x00 0x1d 0x1e 0x1f 0x1c // ;08
"*+/01234" // ;09
"56789-,." // ;0a
]
// ;-------------------------------------
data vdp_bios = byte [
0x00 0x80 0x70 0x81 0x00 0x82 0x01 0x84
0xf5 0x87 0x00 0x40
]
// -- begin: statements.asm
// ; C-BASIC statements
// ;
// ; Copyright (c) 2005 BouKiCHi. All rights reserved.
// ;
// ;
// ; Redistribution and use in source and binary forms, with or without
// ; modification, are permitted provided that the following conditions
// ; are met:
// ; 1. Redistributions of source code must retain the above copyright
// ; notice, this list of conditions and the following disclaimer.
// ; 2. Redistributions in binary form must reproduce the above copyright
// ; notice, this list of conditions and the following disclaimer in the
// ; documentation and/or other materials provided with the distribution.
// ;
// ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// ; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ;
// ;
// ; part of ROM Basic
org> 0x3193
// ;-----------------------------
// ;$3193 - Multiply
// ; In : HL,DE
// ; Out : HL and DAC
// ; Regs : unknown
// ; Note : this routine is not correctly yet
proc multiple() { /*unused*/
BC -push
HL -push
BC -pop
multiple_lp: /*local*/
DE --
@E | D
JR Z? multiple_fin
HL + BC
JR multiple_lp
multiple_fin: /*local*/
BC -pop
return
}
proc rombas() { /*unused*/
HL -push
AF -push
HL <- rombas_text
print_debug()
@0x20 -out 0x2e
@D -out 0x2f
@E -out 0x2f
AF -pop
HL -pop
return
data rombas_text = byte [ /*local*/
"ROMBAS" 0
]
org> 0x392e
data word [
// ; runloop table
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy
]
// ; statement table
org> 0x39de
data word [
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
rombas_niy rombas_niy rombas_niy
]
rombas_niy: /*local*/
HL -push
AF -push
HL <- rombas_niy_text
print_debug()
AF -pop
HL -pop
return
data rombas_niy_text = byte [ /*local*/
"BASIC statements are not implemented yet" 0
]
}
// -- end: statements.asm
// ; FM Music Macro is calling the routine(seems to display message).
// ; in : HL(an address of string with null termination)
org> 0x6678
CALL prn_text // ; as a substitution
// ; ????
org> 0x77cd
RET
// ; Note: Below are a bunch of routines which do not adhere to any API that
// ; I know of. They are called directly by the NMS8250 disk ROM.
// ; For comparing the behaviour of the C-BIOS disk ROM which is under
// ; development with the known working NMS8250 disk ROM it is useful
// ; to be able to run either disk ROM in a C-BIOS machine. Therefore we
// ; have stubs for the routines that the NMS8250 disk ROM may call.
// ; NMS8250 disk ROM can call to this address.
org> 0x7d17
PUSH HL
PUSH AF
LD HL unk7D17_text
CALL print_debug
POP AF
POP HL
RET
data unk7D17_text = byte [
"unknown@7D17" 0
]
// ; NMS8250 disk ROM retrieves a pointer from this address.
org> 0x7d2f
data word [call_sdfscr]
// ; NMS8250 disk ROM can call to this address.
org> 0x7d31
// ; Restore screen parameters from RTC and print welcome message.
LD IX 0x0189 // ; SETSCR
CALL extrom
// ; Print BASIC copyright message.
RET
// ; NMS8250 disk ROM calls to this address.
// ; Restore screen parameters from RTC.
proc call_sdfscr() {
IX <- 0x0185 // ; SDFSCR
JP extrom
// ; NMS8250 disk ROM can call to this address.
org> 0x7e14
HL -push
AF -push
HL <- unk7E14_text
print_debug()
AF -pop
HL -pop
return
data unk7E14_text = byte [ /*local*/
"unknown@7E14" 0
]
// ; FM Music Macro is calling this unknown routine.
org> 0x7e6b
return
org> 0x8000
}
// ; vim:ts=8:expandtab:filetype=z8a:syntax=z8a:
// -- end: main.asm
// ; vim:ts=8:expandtab:filetype=z8a:syntax=z8a:
// -- end: main_msx1_jp.asm
}