From 178662a911cf4dffce8b3bff35c9681ff968d663 Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Mon, 19 Jul 2021 07:55:07 +0100 Subject: [PATCH] First commit. C64, C16/+4 and PET 4016/4032 working. --- .gitignore | 6 + Makefile | 26 ++ c64.asm | 483 ++++++++++++++++++++ c8loader-cbmdos.asm | 103 +++++ ch8asm.py | 293 ++++++++++++ ch8dis.py | 143 ++++++ chip-8.asm | 816 ++++++++++++++++++++++++++++++++++ chipty5-64.asm | 230 ++++++++++ chipty5-pet40.asm | 237 ++++++++++ chipty5-plus4.asm | 230 ++++++++++ crtc.asm | 15 + diags/grid.ch8asm | 16 + diags/keypad.ch8asm | 9 + diags/sound.ch8asm | 4 + display-pet40.asm | 349 +++++++++++++++ layout.asm | 11 + macros.asm | 60 +++ pet.asm | 195 ++++++++ plus4.asm | 585 ++++++++++++++++++++++++ run-tests.sh | 52 +++ samples/15puzzle.ch8 | Bin 0 -> 384 bytes samples/delaytest.ch8 | Bin 0 -> 58 bytes samples/ibmlogo.ch8 | Bin 0 -> 132 bytes samples/invaders.ch8 | Bin 0 -> 1283 bytes samples/lunarlander.ch8 | Bin 0 -> 1792 bytes samples/opcodes.ch8 | Bin 0 -> 478 bytes samples/pong.ch8 | Bin 0 -> 246 bytes samples/rndtest.ch8 | Bin 0 -> 34 bytes samples/tetris.ch8 | Bin 0 -> 494 bytes samples/worm.ch8 | Bin 0 -> 677 bytes sid.asm | 52 +++ ted.asm | 43 ++ template.asm | 13 + tests/add.ch8asm | 36 ++ tests/add.registers.regex | 1 + tests/bcd.ch8asm | 12 + tests/bcd.ram.regex | 1 + tests/bcd.registers.regex | 1 + tests/bit.ch8asm | 37 ++ tests/bit.registers.regex | 1 + tests/call.ch8asm | 21 + tests/call.registers.regex | 1 + tests/hexspr.ch8asm | 21 + tests/hexspr.display.pbm | 34 ++ tests/ld.ch8asm | 17 + tests/ld.ram.regex | 1 + tests/ld.registers.regex | 1 + tests/registers.header.txt | 1 + tests/skip.ch8asm | 37 ++ tests/skip.registers.regex | 1 + tests/sprites.ch8asm | 86 ++++ tests/sprites.display.pbm | 34 ++ tests/sprites.registers.regex | 1 + tests/sub.ch8asm | 31 ++ tests/sub.registers.regex | 1 + via.asm | 32 ++ vic2.asm | 76 ++++ 57 files changed, 4456 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 c64.asm create mode 100644 c8loader-cbmdos.asm create mode 100755 ch8asm.py create mode 100755 ch8dis.py create mode 100644 chip-8.asm create mode 100644 chipty5-64.asm create mode 100644 chipty5-pet40.asm create mode 100644 chipty5-plus4.asm create mode 100644 crtc.asm create mode 100644 diags/grid.ch8asm create mode 100644 diags/keypad.ch8asm create mode 100644 diags/sound.ch8asm create mode 100644 display-pet40.asm create mode 100644 layout.asm create mode 100644 macros.asm create mode 100644 pet.asm create mode 100644 plus4.asm create mode 100755 run-tests.sh create mode 100644 samples/15puzzle.ch8 create mode 100644 samples/delaytest.ch8 create mode 100644 samples/ibmlogo.ch8 create mode 100644 samples/invaders.ch8 create mode 100644 samples/lunarlander.ch8 create mode 100644 samples/opcodes.ch8 create mode 100644 samples/pong.ch8 create mode 100644 samples/rndtest.ch8 create mode 100644 samples/tetris.ch8 create mode 100644 samples/worm.ch8 create mode 100644 sid.asm create mode 100644 ted.asm create mode 100644 template.asm create mode 100644 tests/add.ch8asm create mode 100644 tests/add.registers.regex create mode 100644 tests/bcd.ch8asm create mode 100644 tests/bcd.ram.regex create mode 100644 tests/bcd.registers.regex create mode 100644 tests/bit.ch8asm create mode 100644 tests/bit.registers.regex create mode 100644 tests/call.ch8asm create mode 100644 tests/call.registers.regex create mode 100644 tests/hexspr.ch8asm create mode 100644 tests/hexspr.display.pbm create mode 100644 tests/ld.ch8asm create mode 100644 tests/ld.ram.regex create mode 100644 tests/ld.registers.regex create mode 100644 tests/registers.header.txt create mode 100644 tests/skip.ch8asm create mode 100644 tests/skip.registers.regex create mode 100644 tests/sprites.ch8asm create mode 100644 tests/sprites.display.pbm create mode 100644 tests/sprites.registers.regex create mode 100644 tests/sub.ch8asm create mode 100644 tests/sub.registers.regex create mode 100644 via.asm create mode 100644 vic2.asm diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ddf4e1a --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*[%~] +*.py[co] +*.prg +*.lst +*.ll +*.d64 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..dd0e719 --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ +.PHONY: all clean d64 + +ASM=64tass --case-sensitive --ascii -Wall --vice-labels --long-branch + +PRG=chipty5-64.prg chipty5-plus4.prg chipty5-pet40.prg +DIAGS=$(patsubst %.ch8asm,%.ch8,$(wildcard diags/*.ch8asm)) + +all: $(PRG) +d64: chipty5.d64 +clean: + $(RM) *~ *% *.lst *.l *.prg *.d64 diags/*.ch8 + +%.prg : %.asm + $(ASM) -l $(basename $<).l -L $(basename $<).lst -o $@ $^ + +%.ch8 : %.ch8asm + ./ch8asm.py $< + +chipty5-64.prg: c64.asm chipty5-64.asm c8loader-cbmdos.asm macros.asm layout.asm display-pet40.asm chip-8.asm +chipty5-plus4.prg: plus4.asm chipty5-plus4.asm c8loader-cbmdos.asm macros.asm layout.asm display-pet40.asm chip-8.asm +chipty5-pet40.prg: pet.asm chipty5-pet40.asm c8loader-cbmdos.asm macros.asm layout.asm display-pet40.asm chip-8.asm + +chipty5.d64: $(PRG) $(DIAGS) samples/*.ch8 + c1541 -format "$(basename $@),2a" d64 $@ \ + $(foreach prg,$(filter %.prg,$^),-write "$(prg)" "$(notdir $(basename $(prg)))") \ + $(foreach seq,$(filter-out %.prg,$^),-write "$(seq)" "$(notdir $(seq)),s") \ No newline at end of file diff --git a/c64.asm b/c64.asm new file mode 100644 index 0000000..1ea86d5 --- /dev/null +++ b/c64.asm @@ -0,0 +1,483 @@ +; +; Commodore 64 specific constants and memory addresses +; + .proff + + .cpu "6502" + +io .namespace + + .include "vic2.asm" + .include "sid.asm" + + .virtual $d000 +vic2 .dstruct _vic2 + .endvirtual + + .virtual $d400 +sid .dstruct _sid + .endvirtual + + .endnamespace + +BASIC_START = $0801 +BTOK_SYS = $9e +SCREEN_RAM = $0400 + +; Kernal routines + +ACPTR = $ffa5 ; Input byte from serial port +CHKIN = $ffc6 ; Open channel for input +CHKOUT = $ffc9 ; Open a channel for output +CHRIN = $ffcf ; Get a character from the input channel +CHROUT = $ffd2 ; Output a character +CIOUT = $ffa8 ; Transmit a byte over the serial bus +CINT = $ff81 ; Initialize the screen editor and VIC-II Chip +CLALL = $ffe7 ; Close all open files +CLOSE = $ffc3 ; Close a logical file +CLRCHN = $ffcc ; Clear all I/O channels +GETIN = $ffe4 ; Get a character +IOBASE = $fff3 ; Define I/O memory page +IOINIT = $ff84 ; Initialize I/O devices +LISTEN = $ffb1 ; Command a device on the serial bus to listen +LOAD = $ffd5 ; Load RAM from device +MEMBOT = $ff9c ; Set bottom of memory +MEMTOP = $ff99 ; Set the top of RAM +OPEN = $ffc0 ; Open a logical file +PLOT = $fff0 ; Set or retrieve cursor location +RAMTAS = $ff87 ; Perform RAM test +RDTIM = $ffde ; Read system clock +READST = $ffb7 ; Read status word +RESTOR = $ff8a ; Set the top of RAM +SAVE = $ffd8 ; Save memory to a device +SCNKEY = $ff9f ; Scan the keyboard +SCREEN = $ffed ; Return screen format +SECOND = $ff93 ; Send secondary address for LISTEN +SETLFS = $ffba ; Set up a logical file +SETMSG = $ff90 ; Set system message output +SETNAM = $ffbd ; Set up file name +SETTIM = $ffdb ; Set the system clock +SETTMO = $ffa2 ; Set IEEE bus card timeout flag +STOP = $ffe1 ; Check if STOP key is pressed +TALK = $ffb4 ; Command a device on the serial bus to talk +TKSA = $ff96 ; Send a secondary address to a device commanded to talk +UDTIM = $ffea ; Update the system clock +UNLSN = $ffae ; Send an UNLISTEN command +UNTLK = $ffab ; Send an UNTALK command +VECTOR = $ff8d ; Manage RAM vectors + + +; BASIC routines + +STMDSP = $a00c ; BASIC Command Vectors WORD +FUNDSP = $a052 ; BASIC Function Vectors WORD +OPTAB = $a080 ; BASIC Operator Vectors WORD +RESLST = $a09e ; BASIC Command Keyword Table DATA +MSCLST = $a129 ; BASIC Misc. Keyword Table DATA +OPLIST = $a140 ; BASIC Operator Keyword Table DATA +FUNLST = $a14d ; BASIC Function Keyword Table DATA +ERRTAB = $a19e ; Error Message Table DATA +ERRPTR = $a328 ; Error Message Pointers WORD +OKK = $a364 ; Misc. Messages TEXT +FNDFOR = $a38a ; Find FOR/GOSUB Entry on Stack +BLTU = $a3b8 ; Open Space in Memory +GETSTK = $a3fb ; Check Stack Depth +REASON = $a408 ; Check Memory Overlap +OMERR = $a435 ; Output ?OUT OF MEMORY Error +ERROR = $a437 ; Error Routine +ERRFIN = $a469 ; Break Entry +READY = $a474 ; Restart BASIC +MAIN = $a480 ; Input & Identify BASIC Line +MAIN1 = $a49c ; Get Line Number & Tokenise Text +INSLIN = $a4a2 ; Insert BASIC Text +LINKPRG = $a533 ; Rechain Lines +INLIN = $a560 ; Input Line Into Buffer +CRUNCH = $a579 ; Tokenise Input Buffer +FNDLIN = $a613 ; Search for Line Number +SCRTCH = $a642 ; Perform [new] +CLEAR = $a65e ; Perform [clr] +STXPT = $a68e ; Reset TXTPTR +LIST = $a69c ; Perform [list] +QPLOP = $a717 ; Handle LIST Character +FOR = $a742 ; Perform [for] +NEWSTT = $a7ae ; BASIC Warm Start +CKEOL = $a7c4 ; Check End of Program +GONE = $a7e1 ; Prepare to execute statement +GONE3 = $a7ed ; Perform BASIC Keyword +B_RESTOR = $a81d ; Perform [restore] +B_STOP = $a82c ; Perform [stop], [end], break +CONT = $a857 ; Perform [cont] +RUN = $a871 ; Perform [run] +GOSUB = $a883 ; Perform [gosub] +GOTO = $a8a0 ; Perform [goto] +RETURN = $a8d2 ; Perform [return] +DATA = $a8f8 ; Perform [data] +DATAN = $a906 ; Search for Next Statement / Line +IF = $a928 ; Perform [if] +REM = $a93b ; Perform [rem] +ONGOTO = $a94b ; Perform [on] +LINGET = $a96b ; Fetch linnum From BASIC +LET = $a9a5 ; Perform [let] +PUTINT = $a9c4 ; Assign Integer +PTFLPT = $a9d6 ; Assign Floating Point +PUTSTR = $a9d9 ; Assign String +PUTTIM = $a9e3 ; Assign TI$ +GETSPT = $aa2c ; Add Digit to FAC#1 +PRINTN = $aa80 ; Perform [print]# +CMD = $aa86 ; Perform [cmd] +STRDON = $aa9a ; Print String From Memory +PRINT = $aaa0 ; Perform [print] +VAROP = $aab8 ; Output Variable +CRDO = $aad7 ; Output CR/LF +COMPRT = $aae8 ; Handle comma, TAB(, SPC( +STROUT = $ab1e ; Output String +OUTSPC = $ab3b ; Output Format Character +DOAGIN = $ab4d ; Handle Bad Data +GET = $ab7b ; Perform [get] +INPUTN = $aba5 ; Perform [input#] +INPUT = $abbf ; Perform [input] +BUFFUL = $abea ; Read Input Buffer +QINLIN = $abf9 ; Do Input Prompt +READ = $ac06 ; Perform [read] +RDGET = $ac35 ; General Purpose Read Routine +EXINT = $acfc ; Input Error Messages TEXT +NEXT = $ad1e ; Perform [next] +DONEXT = $ad61 ; Check Valid Loop +FRMNUM = $ad8a ; Confirm Result +FRMEVL = $ad9e ; Evaluate Expression in Text +EVAL = $ae83 ; Evaluate Single Term +PIVAL = $aea8 ; Constant - pi DATA +QDOT = $aead ; Continue Expression +PARCHK = $aef1 ; Expression in Brackets +CHKCLS = $aef7 ; Confirm Character +;- = $aef7 ; -test ')'- +;- = $aefa ; -test '('- +;- = $aefd ; -test comma- +SYNERR = $af08 ; Output ?SYNTAX Error +DOMIN = $af0d ; Set up NOT Function +RSVVAR = $af14 ; Identify Reserved Variable +ISVAR = $af28 ; Search for Variable +TISASC = $af48 ; Convert TI to ASCII String +ISFUN = $afa7 ; Identify Function Type +STRFUN = $afb1 ; Evaluate String Function +NUMFUN = $afd1 ; Evaluate Numeric Function +OROP = $afe6 ; Perform [or], [and] +DOREL = $b016 ; Perform <, =, > +NUMREL = $b01b ; Numeric Comparison +STRREL = $b02e ; String Comparison +DIM = $b07e ; Perform [dim] +PTRGET = $b08b ; Identify Variable +ORDVAR = $b0e7 ; Locate Ordinary Variable +NOTFNS = $b11d ; Create New Variable +NOTEVL = $b128 ; Create Variable +ARYGET = $b194 ; Allocate Array Pointer Space +N32768 = $b1a5 ; Constant 32768 in Flpt DATA +FACINX = $b1aa ; FAC#1 to Integer in (AC/YR) +INTIDX = $b1b2 ; Evaluate Text for Integer +AYINT = $b1bf ; FAC#1 to Positive Integer +ISARY = $b1d1 ; Get Array Parameters +FNDARY = $b218 ; Find Array +BSERR = $b245 ; ?BAD SUBSCRIPT/?ILLEGAL QUANTITY +NOTFDD = $b261 ; Create Array +INLPN2 = $b30e ; Locate Element in Array +UMULT = $b34c ; Number of Bytes in Subscript +FRE = $b37d ; Perform [fre] +GIVAYF = $b391 ; Convert Integer in (AC/YR) to Flpt +POS = $b39e ; Perform [pos] +ERRDIR = $b3a6 ; Confirm Program Mode +GETFNM = $b3e1 ; Check Syntax of FN +FNDOER = $b3f4 ; Perform [fn] +STRD = $b465 ; Perform [str$] +STRLIT = $b487 ; Set Up String +PUTNW1 = $b4d5 ; Save String Descriptor +GETSPA = $b4f4 ; Allocate Space for String +GARBAG = $b526 ; Garbage Collection +DVARS = $b5bd ; Search for Next String +GRBPAS = $b606 ; Collect a String +CAT = $b63d ; Concatenate Two Strings +MOVINS = $b67a ; Store String in High RAM +FRESTR = $b6a3 ; Perform String Housekeeping +FREFAC = $b6db ; Clean Descriptor Stack +CHRD = $b6ec ; Perform [chr$] +LEFTD = $b700 ; Perform [left$] +RIGHTD = $b72c ; Perform [right$] +MIDD = $b737 ; Perform [mid$] +PREAM = $b761 ; Pull sTring Parameters +LEN = $b77c ; Perform [len] +LEN1 = $b782 ; Exit String Mode +ASC = $b78b ; Perform [asc] +GTBYTC = $b79b ; Evaluate Text to 1 Byte in XR +VAL = $b7ad ; Perform [val] +STRVAL = $b7b5 ; Convert ASCII String to Flpt +GETNUM = $b7eb ; Get parameters for POKE/WAIT +GETADR = $b7f7 ; Convert FAC#1 to Integer in LINNUM +PEEK = $b80d ; Perform [peek] +POKE = $b824 ; Perform [poke] +WAIT = $b82d ; Perform [wait] +FADDH = $b849 ; Add 0.5 to FAC#1 +FSUB = $b850 ; Perform Subtraction +FADD5 = $b862 ; Normalise Addition +FADD = $b867 ; Perform Addition +NEGFAC = $b947 ; 2's Complement FAC#1 +OVERR = $b97e ; Output ?OVERFLOW Error +MULSHF = $b983 ; Multiply by Zero Byte +FONE = $b9bc ; Table of Flpt Constants DATA +LOG = $b9ea ; Perform [log] +FMULT = $ba28 ; Perform Multiply +MULPLY = $ba59 ; Multiply by a Byte +CONUPK = $ba8c ; Load FAC#2 From Memory +MULDIV = $bab7 ; Test Both Accumulators +MLDVEX = $bad4 ; Overflow / Underflow +MUL10 = $bae2 ; Multiply FAC#1 by 10 +TENC = $baf9 ; Constant 10 in Flpt DATA +DIV10 = $bafe ; Divide FAC#1 by 10 +FDIV = $bb07 ; Divide FAC#2 by Flpt at (AC/YR) +FDIVT = $bb0f ; Divide FAC#2 by FAC#1 +MOVFM = $bba2 ; Load FAC#1 From Memory +MOV2F = $bbc7 ; Store FAC#1 in Memory +MOVFA = $bbfc ; Copy FAC#2 into FAC#1 +MOVAF = $bc0c ; Copy FAC#1 into FAC#2 +ROUND = $bc1b ; Round FAC#1 +SIGN = $bc2b ; Check Sign of FAC#1 +SGN = $bc39 ; Perform [sgn] +ABS = $bc58 ; Perform [abs] +FCOMP = $bc5b ; Compare FAC#1 With Memory +QINT = $bc9b ; Convert FAC#1 to Integer +INT = $bccc ; Perform [int] +FIN = $bcf3 ; Convert ASCII String to a Number in FAC#1 +N0999 = $bdb3 ; String Conversion Constants DATA +INPRT = $bdc2 ; Output 'IN' and Line Number +FOUT = $bddd ; Convert FAC#1 to ASCII String +FOUTIM = $be68 ; Convert TI to String +FHALF = $bf11 ; Table of Constants DATA +SQR = $bf71 ; Perform [sqr] +FPWRT = $bf7b ; Perform power ($) +NEGOP = $bfb4 ; Negate FAC#1 +LOGEB2 = $bfbf ; Table of Constants DATA +EXP = $bfed ; Perform [exp] + +; Miscellaneous + +D6510 = $0000 ; 6510 On-chip Data Direction Register. +R6510 = $0001 ; 6510 On-chip 8-bit Input/Output Register. +TEMP0002 = $0002 ; Unused. Free for user programs. +ADRAY1 = $0003 ; Jump Vector: Convert FAC to Integer in (A/Y) ($B1AA). +ADRAY2 = $0005 ; Jump Vector: Convert Integer in (A/Y) to Floating point in (FAC); ($B391). +CHARAC = $0007 ; Search Character/Temporary Integer during INT. +ENDCHR = $0008 ; Flag: Scan for Quote at end of String. +INTEGR = $0007 ; Temporary Integer during OR/AND. +TRMPOS = $0009 ; Screen Column for last TAB. +VERCK = $000a ; Flag: 0 = Load, 1 = Verify. +COUNT = $000b ; Input Buffer Pointer/Number of Subscripts. +DIMFLG = $000c ; Flag: Default Array dimension. +VALTYP = $000d ; Data type Flag: $00 = Numeric, $FF = String. +INTFLG = $000e ; Data type Flag: $00 = Floating point, $80 = Integer. +GARBFL = $000f ; Flag: DATA scan/List Quote/Garbage collection. +SUBFLG = $0010 ; Flag: Subscript reference/User Function call. +INPFLG = $0011 ; Input Flag: $00 = INPUT, $40 = GET, $98 = READ. +TANSGN = $0012 ; Flag: TAN sign/Comparative result. +CHANNL = $0013 ; File number of current Input Device. +LINNUM = $0014 ; Temporary: Integer value. +TEMPPT = $0016 ; Pointer: Temporary String Stack. +LASTPT = $0017 ; Last temporary String Address. +TEMPST = $0019 ; Stack for temporary Strings. +INDEX = $0022 ; Utility Pointer Area. +INDEX1 = $0022 ; First Utility Pointer. +INDEX2 = $0024 ; Second Utility Pointer. +RESHO = $0026 ; Floating point product of Multiply and Divide. +TXTTAB = $002b ; Pointer: Start of BASIC Text Area ($0801). +VARTAB = $002d ; Pointer: Start of BASIC Variables. +ARYTAB = $002f ; Pointer: Start of BASIC Arrays. +STREND = $0031 ; Pointer: End of BASIC Arrays + 1. +FRETOP = $0033 ; Pointer: Bottom of String space. +FRESPC = $0035 ; Utility String Pointer. +ZMEMSIZ = $0037 ; Pointer: Highest Address available to BASIC ($A000). +CURLIN = $0039 ; Current BASIC Line number. +OLDLIN = $003b ; Previous BASIC Line number. +OLDTXT = $003d ; Pointer: BASIC Statement for CONT. +DATLIN = $003f ; Current DATA Line number. +DATPTR = $0041 ; Pointer: Used by READ - current DATA Item Address. +INPPTR = $0043 ; Pointer: Temporary storage of Pointer during INPUT Routine. +VARNAM = $0045 ; Name of Variable being sought in Variable Table. +VARPNT = $0047 ; Pointer: to value of (VARNAM) if Integer, to descriptor if String. +FORPNT = $0049 ; Pointer: Index Variable for FOR/NEXT loop. +VARTXT = $004b ; Temporary storage for TXTPTR during READ, INPUT and GET. +OPMASK = $004d ; Mask used during FRMEVL. +TEMPF3 = $004e ; Temporary storage for FLPT value. +FOUR6 = $0053 ; Length of String Variable during garbage collection. +JMPER = $0054 ; Jump Vector used in Function Evaluation - JMP followed by Address ($4C,$LB,$MB). +TEMPF1 = $0057 ; Temporary storage for FLPT value. +TEMPF2 = $005c ; Temporary storage for FLPT value. +FAC = $0061 ; Main Floating point Accumulator. +FACEXP = $0061 ; FAC Exponent. +FACHO = $0062 ; FAC Mantissa. +FACSGN = $0066 ; FAC Sign. +SGNFLG = $0067 ; Pointer: Series Evaluation Constant. +BITS = $0068 ; Bit Overflow Area during normalisation Routine. +AFAC = $0069 ; Auxiliary Floating point Accumulator. +ARGEXP = $0069 ; AFAC Exponent. +ARGHO = $006a ; AFAC Mantissa. +ARGSGN = $006e ; AFAC Sign. +ARISGN = $006f ; Sign of result of Arithmetic Evaluation. +FACOV = $0070 ; FAC low-order rounding. +FBUFPT = $0071 ; Pointer: Used during CRUNCH/ASCII conversion. +CHRGET = $0073 ; Subroutine: Get next Byte of BASIC Text. +CHRGOT = $0079 ; Entry to Get same Byte again. +TXTPTR = $007a ; Pointer: Current Byte of BASIC Text. +RNDX = $008b ; Floating RND Function Seed Value. +STATUS = $0090 ; Kernal I/O Status Word ST. +STKEY = $0091 ; Flag: $7F = STOP key. +SVXT = $0092 ; Timing Constant for Tape. +VERCKK = $0093 ; Flag: 0 = Load, 1 = Verify. +C3PO = $0094 ; Flag: Serial Bus - Output Character buffered. +BSOUR = $0095 ; Buffered Character for Serial Bus. +SYNO = $0096 ; Cassette Sync. number. +TEMPX = $0097 ; Temporary storage of X Register during CHRIN. +TEMPY = $0097 ; Temporary storage of Y Register during RS232 fetch. +LDTND = $0098 ; Number of Open Files/Index to File Table. +DFLTN = $0099 ; Default Input Device (0). +DFLTO = $009a ; Default Output Device (3). +PRTY = $009b ; Parity of Byte Output to Tape. +DPSW = $009c ; Flag: Byte received from Tape. +MSGFLG = $009d ; Flag: $00 = Program mode: Suppress Error Messages, $40 = Kernal Error Messages only, $80 = Direct mode: Full Error Messages. +FNMIDX = $009e ; Index to Cassette File name/Header ID for Tape write. +PTR1 = $009e ; Tape Error log pass 1. +PTR2 = $009f ; Tape Error log pass 2. +TIME = $00a0 ; Real-time jiffy Clock (Updated by IRQ Interrupt approx. every 1/60 of Second); Update Routine: UDTIMK ($F69B). +TSFCNT = $00a3 ; Bit Counter Tape Read or Write/Serial Bus EOI (End Of Input) Flag. +TBTCNT = $00a4 ; Pulse Counter Tape Read or Write/Serial Bus shift Counter. +CNTDN = $00a5 ; Tape Synchronising count down. +BUFPNT = $00a6 ; Pointer: Tape I/O buffer. +INBIT = $00a7 ; RS232 temporary for received Bit/Tape temporary. +BITC1 = $00a8 ; RS232 Input Bit count/Tape temporary. +RINONE = $00a9 ; RS232 Flag: Start Bit check/Tape temporary. +RIDATA = $00aa ; RS232 Input Byte Buffer/Tape temporary. +RIPRTY = $00ab ; RS232 Input parity/Tape temporary. +SAL = $00ac ; Pointer: Tape Buffer/Screen scrolling. +EAL = $00ae ; Tape End Address/End of Program. +CMPO = $00b0 ; Tape timing Constants. +TAPE1 = $00b2 ; Pointer: Start Address of Tape Buffer ($033C). +BITTS = $00b4 ; RS232 Write bit count/Tape Read timing Flag. +NXTBIT = $00b5 ; RS232 Next Bit to send/Tape Read - End of Tape. +RODATA = $00b6 ; RS232 Output Byte Buffer/Tape Read Error Flag. +FNLEN = $00b7 ; Number of Characters in Filename. +LA = $00b8 ; Current File - Logical File number. +SA = $00b9 ; Current File - Secondary Address. +FA = $00ba ; Current File - First Address (Device number). OPEN LA,FA,SA; OPEN 1,8,15,"I0":CLOSE 1 +FNADR = $00bb ; Pointer: Current File name Address. +ROPRTY = $00bd ; RS232 Output Parity/Tape Byte to be Input or Output. +FSBLK = $00be ; Tape Input/Output Block count. +MYCH = $00bf ; Serial Word Buffer. +CAS1 = $00c0 ; Tape Motor Switch. +STAL = $00c1 ; Start Address for LOAD and Cassette Write. +MEMUSS = $00c3 ; Pointer: Type 3 Tape LOAD and general use. +LSTX = $00c5 ; Matrix value of last Key pressed; No Key = $40. +NDX = $00c6 ; Number of Characters in Keyboard Buffer queue. +RVS = $00c7 ; Flag: Reverse On/Off; On = $01, Off = $00. +INDX = $00c8 ; Pointer: End of Line for Input (Used to suppress trailing spaces). +LXSP = $00c9 ; Cursor X/Y (Line/Column) position at start of Input. +SFDX = $00cb ; Flag: Print shifted Characters. +BLNSW = $00cc ; Flag: Cursor blink; $00 = Enabled, $01 = Disabled. +BLNCT = $00cd ; Timer: Count down for Cursor blink toggle. +GDBLN = $00ce ; Character under Cursor while Cursor Inverted. +BLNON = $00cf ; Flag: Cursor Status; $00 = Off, $01 = On. +CRSW = $00d0 ; Flag: Input from Screen = $03, or Keyboard = $00. +PNT = $00d1 ; Pointer: Current Screen Line Address. +PNTR = $00d3 ; Cursor Column on current Line, including Wrap-round Line, if any. +QTSW = $00d4 ; Flag: Editor in Quote Mode; $00 = Not. +LNMX = $00d5 ; Current logical Line length: 39 or 79. +TBLX = $00d6 ; Current Screen Line number of Cursor. +SCHAR = $00d7 ; Screen value of current Input Character/Last Character Output. +INSRT = $00d8 ; Count of number of inserts outstanding. +LDTB1 = $00d9 ; Screen Line link Table/Editor temporaries. High Byte of Line Screen Memory Location. +USER = $00f3 ; Pointer: Current Colour RAM Location. +KEYTAB = $00f5 ; Vector: Current Keyboard decoding Table. ($EB81) +RIBUF = $00f7 ; RS232 Input Buffer Pointer. +ROBUF = $00f9 ; RS232 Output Buffer Pointer. +FREKZP = $00fb ; Free Zero Page space for User Programs. +BASZPT = $00ff ; BASIC temporary Data Area. +ASCWRK = $00ff ; Assembly Area for Floating point to ASCII conversion. +BAD = $0100 ; Tape Input Error log. +STACK = $0100 ; 6510 Hardware Stack Area. +BSTACK = $013f ; BASIC Stack Area. +BUF = $0200 ; BASIC Input Buffer (Input Line from Screen). +LAT = $0259 ; Kernal Table: Active logical File numbers. +FAT = $0263 ; Kernal Table: Active File First Addresses (Device numbers). +SAT = $026d ; Kernal Table: Active File Secondary Addresses. +KEYD = $0277 ; Keyboard Buffer Queue (FIFO). +MEMSTR = $0281 ; Pointer: Bottom of Memory for Operating System ($0800). +MEMSIZ = $0283 ; Pointer: Top of Memory for Operating System ($A000). +TIMOUT = $0285 ; Serial IEEE Bus timeout defeat Flag. +COLOR = $0286 ; Current Character Colour code. +GDCOL = $0287 ; Background Colour under Cursor. +HIBASE = $0288 ; High Byte of Screen Memory Address ($04). +XMAX = $0289 ; Maximum number of Bytes in Keyboard Buffer ($0A). +RPTFLG = $028a ; Flag: Repeat keys; $00 = Cursors, INST/DEL & Space repeat, $40 no Keys repeat, $80 all Keys repeat ($00). +KOUNT = $028b ; Repeat Key: Speed Counter ($04). +DELAY = $028c ; Repeat Key: First repeat delay Counter ($10). +SHFLAG = $028d ; Flag: Shift Keys: Bit 1 = Shift, Bit 2 = CBM, Bit 3 = CTRL; ($00 = None, $01 = Shift, etc.). +LSTSHF = $028e ; Last Shift Key used for debouncing. +KEYLOG = $028f ; Vector: Routine to determine Keyboard table to use based on Shift Key Pattern ($EB48). +MODE = $0291 ; Flag: Upper/Lower Case change: $00 = Disabled, $80 = Enabled ($00). +AUTODN = $0292 ; Flag: Auto scroll down: $00 = Disabled ($00). +M51CTR = $0293 ; RS232 Pseudo 6551 control Register Image. +M51CDR = $0294 ; RS232 Pseudo 6551 command Register Image. +M51AJB = $0295 ; RS232 Non-standard Bits/Second. +RSSTAT = $0297 ; RS232 Pseudo 6551 Status Register Image. +BITNUM = $0298 ; RS232 Number of Bits left to send. +BAUDOF = $0299 ; RS232 Baud Rate; Full Bit time microseconds. +RIDBE = $029b ; RS232 Index to End of Input Buffer. +RIDBS = $029c ; RS232 Pointer: High Byte of Address of Input Buffer. +RODBS = $029d ; RS232 Pointer: High Byte of Address of Output Buffer. +RODBE = $029e ; RS232 Index to End of Output Buffer. +IRQTMP = $029f ; Temporary store for IRQ Vector during Tape operations. +ENABL = $02a1 ; RS232 Enables. +TODSNS = $02a2 ; TOD sense during Tape I/O. +TRDTMP = $02a3 ; Temporary storage during Tape READ. +TD1IRQ = $02a4 ; Temporary D1IRQ Indicator during Tape READ. +TLNIDX = $02a5 ; Temporary for Line Index. +TVSFLG = $02a6 ; Flag: TV Standard: $00 = NTSC, $01 = PAL. +TEMP02a7 = $02a7 ; Unused. +SPR11 = $02c0 ; Sprite #11 Data Area. (SCREEN + $03F8 + SPR number) POKE 1024+1016+0,11 to use Sprite#0 DATA from ($02C0-$02FE). +IERROR = $0300 ; Vector: Indirect entry to BASIC Error Message, (X) points to Message ($E38B). +IMAIN = $0302 ; Vector: Indirect entry to BASIC Input Line and Decode ($A483). +ICRNCH = $0304 ; Vector: Indirect entry to BASIC Tokenise Routine ($A57C). +IQPLOP = $0306 ; Vector: Indirect entry to BASIC LIST Routine ($A71A). +IGONE = $0308 ; Vector: Indirect entry to BASIC Character dispatch Routine ($A7E4). +IEVAL = $030a ; Vector: Indirect entry to BASIC Token evaluation ($AE86). +SAREG = $030c ; Storage for 6510 Accumulator during SYS. +SXREG = $030d ; Storage for 6510 X-Register during SYS. +SYREG = $030e ; Storage for 6510 Y-Register during SYS. +SPREG = $030f ; Storage for 6510 Status Register during SYS. +USRPOK = $0310 ; USR Function JMP Instruction ($4C). +USRADD = $0311 ; USR Address ($LB,$MB). +TEMP0313 = $0313 ; Unused. +CINV = $0314 ; Vector: Hardware IRQ Interrupt Address ($EA31). +CNBINV = $0316 ; Vector: BRK Instruction Interrupt Address ($FE66). +NMINV = $0318 ; Vector: Hardware NMI Interrupt Address ($FE47). +IOPEN = $031a ; Vector: Indirect entry to Kernal OPEN Routine ($F34A). +ICLOSE = $031c ; Vector: Indirect entry to Kernal CLOSE Routine ($F291). +ICHKIN = $031e ; Vector: Indirect entry to Kernal CHKIN Routine ($F20E). +ICKOUT = $0320 ; Vector: Indirect entry to Kernal CHKOUT Routine ($F250). +ICLRCH = $0322 ; Vector: Indirect entry to Kernal CLRCHN Routine ($F333). +IBASIN = $0324 ; Vector: Indirect entry to Kernal CHRIN Routine ($F157). +IBSOUT = $0326 ; Vector: Indirect entry to Kernal CHROUT Routine ($F1CA). +ISTOP = $0328 ; Vector: Indirect entry to Kernal STOP Routine ($F6ED). +IGETIN = $032a ; Vector: Indirect entry to Kernal GETIN Routine ($F13E). +ICLALL = $032c ; Vector: Indirect entry to Kernal CLALL Routine ($F32F). +USRCMD = $032e ; User Defined Vector ($FE66). +ILOAD = $0330 ; Vector: Indirect entry to Kernal LOAD Routine ($F4A5). +ISAVE = $0332 ; Vector: Indirect entry to Kernal SAVE Routine ($F5ED). +TEMP0334 = $0334 ; Unused. +TBUFFR = $033c ; Tape I/O Buffer. +SPR13 = $0340 ; Sprite #13. +SPR14 = $0380 ; Sprite #14. +SPR15 = $03c0 ; Sprite #15. +TEMP03fc = $03fc ; Unused. +VICSCN = $0400 ; Default Screen Video Matrix. +TEMP07e8 = $07e8 ; Unused. +SPNTRS = $07f8 ; Default Sprite Data Pointers. + + .pron + +; vim: syntax=64tass \ No newline at end of file diff --git a/c8loader-cbmdos.asm b/c8loader-cbmdos.asm new file mode 100644 index 0000000..0bf6676 --- /dev/null +++ b/c8loader-cbmdos.asm @@ -0,0 +1,103 @@ +.weak +IS_PET = false +.endweak + +.if IS_PET +cbmopen .macro filedes, device, secaddr, filenameptr, filenamelen + lda #\filedes + sta LA + lda #\device + sta FA + lda #\secaddr + sta SA + lda \filenamelen + sta FNLEN + lda #<\filenameptr + sta FNADR + lda #>\filenameptr + sta FNADR+1 + + jsr OPEN + lda STATUS + beq + + sec + bcs ++ ++ clc ++ + .endmacro + +cbmstatus .macro + lda STATUS + .endmacro +.else +cbmopen .macro filedes, device, secaddr, filenameptr, filenamelen + lda \filenamelen + ldx #<\filenameptr + ldy #>\filenameptr + jsr SETNAM + + lda #\filedes + ldx FA + bne + + ldx #\device ++ ldy #\secaddr + jsr SETLFS + + jsr OPEN + .endmacro + +cbmstatus .macro + jsr READST + .endmacro +.endif + + .section code +LoadCH8 .proc + + .cbmopen 2, 8, 2, ch8filename, ch8filenamelen + bcs error + + ldx #2 + jsr CHKIN + + lda #C8ENTRY + sta EAL+1 + + ldy #0 +- .cbmstatus + bne eof + jsr CHRIN + sta (EAL), y + inc EAL + bne + + inc EAL+1 ++ jmp - + +eof and #$40 + beq readerror + +close lda #2 + jsr CLOSE + + jsr CLRCHN + rts + +error ; TODO + lda #4 + sta $d020 + jmp close + +readerror ; TODO + lda #1 + sta $d020 + jmp close + .endproc + .endsection code + + .section data +ch8filenamelen .byte ? +ch8filename .text "tetris.ch8" + .fill 16 + .endsection data diff --git a/ch8asm.py b/ch8asm.py new file mode 100755 index 0000000..b086589 --- /dev/null +++ b/ch8asm.py @@ -0,0 +1,293 @@ +#!/usr/bin/env python3 + +from typing import NamedTuple +import re, struct + + +class Token(NamedTuple): + type: str + value: str + filename: str + line: int + column: int + + +TOKENS = [ + ( + "MNEMONIC", + "|".join( + [ + "CLS", + "RET", + "SYS", + "JP", + "CALL", + "SE", + "LD", + "ADD", + "AND", + "OR", + "XOR", + "SUBN", + "SUB", + "SHR", + "SHL", + "SNE", + "RND", + "DRW", + "SKP", + "SKNP", + "DATA", + "EXIT", + ] + ), + ), + ("VREG", r"V[0-9a-fA-F]"), + ("PREG", r"ST|DT|F|B|\[I\]|I|K"), + ("NUMBER", r"[0-9a-fA-F]{1,4}"), + ("SYMBOL", r"[a-zA-Z_.]+[a-zA-Z_.0-9]*"), + ("COMMA", r","), + ("COLON", r":"), + ("STAR", r"\*"), + ("EQUAL", r"="), + ("SPACE", r"[ \t]+"), + ("MISMATCH", r"."), +] + +TOK_RE = re.compile("|".join([f"(?P<{tn}>{tp})" for tn, tp in TOKENS])) + + +def tokenize_line(line, filename="", lineno=-1): + line = line.split(";", 1)[0] + if len(line) < 1: + return [] + r = [] + for match in TOK_RE.finditer(line): + t = Token( + type=match.lastgroup, + value=match.group(), + filename=filename, + line=lineno, + column=match.start(), + ) + if t.type == "SPACE": + continue + r.append(t) + return r + + +def tokenize_file(filename): + with open(filename, "r") as f: + lineno = 1 + for line in f: + yield tokenize_line(line, filename, lineno) + lineno += 1 + + +class ParseError(Exception): + pass + + +def ensure_size(val, bits): + if val.type not in ("NUMBER", "SYMBOL"): + raise ParseError(f"Literal value expected, found {val} instead") + if type(val.value) == str: + v = int(val.value, 16) + else: + v = val.value + if v >= (1 << bits): + raise ParseError(f"Value to large for {bits} bits: {val}") + return v + + +def vreg_index(tok): + if tok.type != "VREG": + raise ParseError(f"V register expected, found {tok} instead") + return int(tok.value[-1], 16) + + +def assemble_instruction(tl, symbols): + if type(tl) == int: + return tl + if tl[0].type != "MNEMONIC": + raise ParseError("Mnemonic was expected but found " + repr(tl[0])) + mnemonic = tl[0].value + ntok = len(tl) + for i in range(len(tl)): + if tl[i].type in ("SYMBOL", "STAR"): + if tl[i].value in symbols: + nt = Token( + type="NUMBER", + value=symbols[tl[i].value], + filename=tl[i].filename, + line=tl[i].line, + column=tl[i].column, + ) + tl[i] = nt + else: + return tl + if ntok == 1: + if mnemonic == "CLS": + return 0x00E0 + elif mnemonic == "RET": + return 0x00EE + elif mnemonic == "EXIT": + return 0x00fd + else: + raise ParseError("Invalid number of operands for " + tl[0].value) + elif ntok == 2: + op1 = tl[1] + if mnemonic == "SYS": + return 0x0000 | ensure_size(op1, 12) + if mnemonic == "JP": + return 0x1000 | ensure_size(op1, 12) + if mnemonic == "CALL": + return 0x2000 | ensure_size(op1, 12) + if mnemonic == "DATA": + return ensure_size(op1, 16) + if mnemonic == "SKP": + return 0xE09E | (vreg_index(op1) << 8) + if mnemonic == "SKNP": + return 0xE0A1 | (vreg_index(op1) << 8) + if mnemonic == "SHR": + return 0x8006 | vreg_index(op1) << 8 | vreg_index(op1) << 4 + if mnemonic == "SHL": + return 0x800E | vreg_index(op1) << 8 | vreg_index(op1) << 4 + else: + raise ParseError("Invalid number of operands for " + tl[0].value) + elif ntok == 3: + op1 = tl[1] + op2 = tl[2] + if mnemonic == "SE": + if op2.type == "VREG": + return 0x5000 | vreg_index(op1) << 8 | vreg_index(op2) << 4 + else: + return 0x3000 | vreg_index(op1) << 8 | ensure_size(op2, 8) + if mnemonic == "SNE": + if op2.type == "VREG": + return 0x9000 | vreg_index(op1) << 8 | vreg_index(op2) << 4 + else: + return 0x4000 | vreg_index(op1) << 8 | ensure_size(op2, 8) + if mnemonic == "LD": + if op1.type == "VREG": + if op2.type == "VREG": + return 0x8000 | vreg_index(op1) << 8 | vreg_index(op2) << 4 + elif op2.type == "PREG": + if op2.value == "DT": + return 0xF007 | (vreg_index(op1) << 8) + elif op2.value == "K": + return 0xF00A | (vreg_index(op1) << 8) + elif op2.value == "[I]": + return 0xF065 | (vreg_index(op1) << 8) + elif op2.value == "R": + return 0xF085 | (vreg_index(op1) << 8) + else: + raise ParseError() + elif op2.type == "NUMBER": + return 0x6000 | vreg_index(op1) << 8 | ensure_size(op2, 8) + elif op1.type == "PREG": + if op1.value == "I": + return 0xA000 | ensure_size(op2, 12) + elif op1.value == "DT": + return 0xF015 | (vreg_index(op2) << 8) + elif op1.value == "ST": + return 0xF018 | (vreg_index(op2) << 8) + elif op1.value == "F": + return 0xF029 | (vreg_index(op2) << 8) + elif op1.value == "B": + return 0xF033 | (vreg_index(op2) << 8) + elif op1.value == "[I]": + return 0xF055 | (vreg_index(op2) << 8) + else: + raise ParseError() + else: + raise ParseError() + if mnemonic == "ADD": + if op1.type == "VREG": + if op2.type == "VREG": + return 0x8004 | vreg_index(op1) << 8 | vreg_index(op2) << 4 + elif op2.type == "NUMBER": + return 0x7000 | vreg_index(op1) << 8 | ensure_size(op2, 8) + elif op1.value == "I": + return 0xF01E | vreg_index(op2) << 8 + else: + raise ParseError() + if mnemonic == "OR": + return 0x8001 | vreg_index(op1) << 8 | vreg_index(op2) << 4 + if mnemonic == "AND": + return 0x8002 | vreg_index(op1) << 8 | vreg_index(op2) << 4 + if mnemonic == "XOR": + return 0x8003 | vreg_index(op1) << 8 | vreg_index(op2) << 4 + if mnemonic == "SUB": + return 0x8005 | vreg_index(op1) << 8 | vreg_index(op2) << 4 + if mnemonic == "SUBN": + return 0x8007 | vreg_index(op1) << 8 | vreg_index(op2) << 4 + if mnemonic == "SHR": + return 0x8006 | vreg_index(op1) << 8 | vreg_index(op2) << 4 + if mnemonic == "SHL": + return 0x800E | vreg_index(op1) << 8 | vreg_index(op2) << 4 + if mnemonic == "JP": + if op1.type != "VREG" or op1.value != "V0": + raise ParseError(f"Register V0 expected. {op1} found instead") + return 0xB000 | ensure_size(op1, 12) + if mnemonic == "RND": + return 0xC000 | vreg_index(op1) << 8 | ensure_size(op2, 8) + elif ntok == 4: + if mnemonic == "DRW": + op1 = tl[1] + op2 = tl[2] + op3 = tl[3] + return ( + 0xD000 + | vreg_index(op1) << 8 + | vreg_index(op2) << 4 + | ensure_size(op3, 4) + ) + else: + raise ParseError() + else: + raise ParseError("Invalid number of operands for " + tl[0].value) + return tl + + +def assemble(filename): + addr = 0x200 + symbols = {} + opcodes = [] + for tokline in tokenize_file(filename): + if len(tokline) < 1: + continue + symbols["*"] = addr + len(opcodes) * 2 + if tokline[0].type == "SYMBOL": + sym = tokline[0].value + tokline = tokline[1:] + if tokline[0].type == "COLON": + tokline = tokline[1:] + if tokline[0].type == "EQUAL": + symbols[sym] = ensure_size(tokline[1], 32) + continue + symbols[sym] = symbols["*"] + tokline = [t for t in tokline if t.type != "COMMA"] + if len(tokline) < 1: + continue + opcodes.append(assemble_instruction(tokline, symbols)) + addr = 0x200 + for o in opcodes: + symbols["*"] = addr + yield assemble_instruction(o, symbols) + addr += 2 + + +if __name__ == "__main__": + import sys + + for fn in sys.argv[1:]: + if "." in fn: + ofn = fn[: fn.rindex(".")] + ".ch8" + else: + ofn = fn + ".ch8" + with open(ofn, "wb") as of: + for word in assemble(fn): + if type(word) != int: + print(word) + of.write(struct.pack(">H", word)) diff --git a/ch8dis.py b/ch8dis.py new file mode 100755 index 0000000..aa56432 --- /dev/null +++ b/ch8dis.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 + +import struct + + +OP = [ + # Mnemonic, mask, value, xmask, ymask, kmask, klabel + ('CLS', '', + 0xffff, 0x00e0, 0x0000, 0x0000, 0x0000, False), + ('RET', '', + 0xffff, 0x00ee, 0x0000, 0x0000, 0x0000, False), + ('SYS', '{k}', + 0xf000, 0x0000, 0x0000, 0x0000, 0x0fff, True), + ('JP', '{k}', + 0xf000, 0x1000, 0x0000, 0x0000, 0x0fff, True), + ('CALL', '{k}', + 0xf000, 0x2000, 0x0000, 0x0000, 0x0fff, True), + ('SE', 'V{x:01x}, {k:02x}', + 0xf000, 0x3000, 0x0f00, 0x0000, 0x00ff, False), + ('SNE', 'V{x:01x}, {k:02x}', + 0xf000, 0x4000, 0x0f00, 0x0000, 0x00ff, False), + ('SE', 'V{x:01x}, V{y:01x}', + 0xf00f, 0x5000, 0x0f00, 0x00f0, 0x0000, False), + ('LD', 'V{x:01x}, {k:02x}', + 0xf000, 0x6000, 0x0f00, 0x0000, 0x00ff, False), + ('ADD', 'V{x:01x}, {k:02x}', + 0xf000, 0x7000, 0x0f00, 0x0000, 0x00ff, False), + ('LD', 'V{x:01x}, V{y:01x}', + 0xf00f, 0x8000, 0x0f00, 0x00f0, 0x0000, False), + ('OR', 'V{x:01x}, V{y:01x}', + 0xf00f, 0x8001, 0x0f00, 0x00f0, 0x0000, False), + ('AND', 'V{x:01x}, V{y:01x}', + 0xf00f, 0x8002, 0x0f00, 0x00f0, 0x0000, False), + ('XOR', 'V{x:01x}, V{y:01x}', + 0xf00f, 0x8003, 0x0f00, 0x00f0, 0x0000, False), + ('ADD', 'V{x:01x}, V{y:01x}', + 0xf00f, 0x8004, 0x0f00, 0x00f0, 0x0000, False), + ('SUB', 'V{x:01x}, V{y:01x}', + 0xf00f, 0x8005, 0x0f00, 0x00f0, 0x0000, False), + ('SHR', 'V{x:01x}, V{y:01x}', + 0xf00f, 0x8006, 0x0f00, 0x00f0, 0x0000, False), + ('SHL', 'V{x:01x}, V{y:01x}', + 0xf00f, 0x800e, 0x0f00, 0x00f0, 0x0000, False), + ('SNE', 'V{x:01x}, V{y:01x}', + 0xf00f, 0x9000, 0x0f00, 0x00f0, 0x0000, False), + ('LD', 'I, {k}', + 0xf000, 0xa000, 0x0000, 0x0000, 0x0fff, True), + ('JP', 'V0, {k}', + 0xf000, 0xb000, 0x0000, 0x0000, 0x0fff, True), + ('RND', 'V{x:01x}, {k:02x}', + 0xf000, 0xc000, 0x0f00, 0x0000, 0x00ff, False), + ('DRW', 'V{x:01x}, V{y:01x}, {k:02x}', + 0xf000, 0xd000, 0x0f00, 0x00f0, 0x000f, False), + ('SKP', 'V{x:01x}', + 0xf0ff, 0xe09e, 0x0f00, 0x0000, 0x0000, False), + ('SKNP', 'V{x:01x}', + 0xf0ff, 0xe0a1, 0x0f00, 0x0000, 0x0000, False), + ('LD', 'V{x:01x}, DT', + 0xf0ff, 0xf007, 0x0f00, 0x0000, 0x0000, False), + ('LD', 'V{x:01x}, K', + 0xf0ff, 0xf00a, 0x0f00, 0x0000, 0x0000, False), + ('LD', 'DT, V{x:01x}', + 0xf0ff, 0xf015, 0x0f00, 0x0000, 0x0000, False), + ('LD', 'ST, V{x:01x}', + 0xf0ff, 0xf018, 0x0f00, 0x0000, 0x0000, False), + ('ADD', 'I, V{x:01x}', + 0xf0ff, 0xf01e, 0x0f00, 0x0000, 0x0000, False), + ('LD', 'F, V{x:01x}', + 0xf0ff, 0xf029, 0x0f00, 0x0000, 0x0000, False), + ('LD', 'B, V{x:01x}', + 0xf0ff, 0xf033, 0x0f00, 0x0000, 0x0000, False), + ('LD', '[I], V{x:01x}', + 0xf0ff, 0xf055, 0x0f00, 0x0000, 0x0000, False), + ('LD', 'V{x:01x}, [I]', + 0xf0ff, 0xf065, 0x0f00, 0x0000, 0x0000, False), + + + ('DATA', '{k:04x}', + 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, False) +] + + +def c8decode(ins): + + def _unmask(v, m): + if m == 0: + return None + r = v & m + while (m & 1) == 0: + m >>= 1 + r >>= 1 + return r + + for mn, fmt, mask, value, xmask, ymask, kmask, klabel in OP: + if (ins & mask) == value: + xo = _unmask(ins, xmask) + yo = _unmask(ins, ymask) + ko = _unmask(ins, kmask) + return (mn, fmt, xo, yo, ko, klabel) + + +def disasm(filename, org=0x200): + pc = org + targets = set() + listing = [] + with open(filename, 'rb') as f: + while True: + w = f.read(2) + if len(w) != 2: + break + instr = struct.unpack('>H', w)[0] + mn, fmt, xo, yo, ko, klabel = c8decode(instr) + if klabel: + targets.add(ko) + listing.append((pc, instr, mn, fmt, xo, yo, ko, klabel)) + pc += 2 + end = pc + + print(f"""; +; {filename} +; start={org:03x} end={end:03x} size={end-org}(dec) +; + """) + for pc, instr, mn, fmt, xo, yo, ko, klabel in listing: + if pc in targets: + label = "l%03x" % (pc,) + else: + label = "" + if klabel: + if org <= ko <= end: + ko = f"l{ko:03x}" + else: + ko = f"{ko:03x}" + o = fmt.format(x=xo, y=yo, k=ko) + print(f"{label:8s} {mn:5s} {o:12s} ; {pc:03x}: {instr:04x}") + + +if __name__ == '__main__': + import sys + + for fn in sys.argv[1:]: + disasm(fn) + diff --git a/chip-8.asm b/chip-8.asm new file mode 100644 index 0000000..b6cb240 --- /dev/null +++ b/chip-8.asm @@ -0,0 +1,816 @@ +; +; CHIP-8 emulation core +; + +EMBEDSAMPLE = true + +EF_SHIFTX = %0000_0001 +EF_REGS = %0001_0000 +EF_LOAD = %0010_0000 +EF_PAUSE = %0100_0000 +EF_RESET = %1000_0000 + +C8START = $0200 + + .section zp +zptr1 .word ? +zptr2 .word ? +pc .word ? + .endsection zp + + .section bss +reg .block +v .fill 16 +i .word ? +sp .byte ? +dt .byte ? +st .byte ? +pc .word ? + .endblock +ins .block +opcode .word ? +c .byte ? +x .byte ? +y .byte ? +w .word ? +ptr .word ? + .endblock +c8stack .fill 48 +rngst .fill 4 +rng_t1 .byte ? +c8screen .fill (64*32)/8 +c8screenend = *-1 +scrdirty .byte ? + .endsection bss + + .section code + +; This is called 60 times per second from the machine specific interrupt +; handler +Tick .proc + lda reg.dt + beq + + dec reg.dt ++ lda reg.st + beq + + dec reg.st + bne + + jsr SoundOff ++ rts + .endproc + +C8Reset .proc + .CopyMem sprites, C8RAM, size(sprites) + ;.FillMem C8RAM+size(sprites), 0, C8RAMSIZE-size(sprites) + .if EMBEDSAMPLE + .CopyMem samplecode, C8RAM+C8START, size(samplecode) + .endif +warm .FillMem reg, 0, size(reg) + jsr c8cls + jsr SoundOff + .if (C8START & $ff) != 0 + lda #> 8) != 0 + lda #>C8START + sta reg.pc+1 + .endif + lda eflags + and #~EF_RESET + sta eflags + rts + .endproc + +C8Run .proc + jsr C8Reset + +fetch + jsr HeartBeat + lda eflags + tax + and #EF_REGS + beq + + jsr ShowRegisters ++ txa + and #EF_RESET + beq + + lda eflags + and #~EF_RESET + sta eflags + jsr C8Reset.warm + jmp fetch ++ txa + and #EF_PAUSE + beq + + jsr VideoDraw +- lda eflags + and #EF_PAUSE + bne - ++ txa + and #EF_LOAD + beq + + lda eflags + and #~EF_LOAD + sta eflags + jsr InputFileName + lda ch8filenamelen + beq + + jsr LoadCH8 + jsr C8Reset.warm + jmp fetch ++ lda scrdirty + beq + + jsr GetVBlank + bcs + + jsr VideoDraw + ++ clc + lda #C8RAM + adc reg.pc+1 + sta pc+1 + ; advance reg.pc + clc + lda #2 + adc reg.pc + sta reg.pc + lda #0 + adc reg.pc+1 + sta reg.pc+1 + +decode + ldy #0 + lda (pc), y + sta ins.opcode+1 + and #$0f + sta ins.w+1 + sta ins.x + lda (pc), y + lsr a + lsr a + lsr a + lsr a + sta ins.c + iny + lda (pc), y + sta ins.opcode + sta ins.w + lsr a + lsr a + lsr a + lsr a + sta ins.y + lda ins.c + cmp #8 + bne + + ; decode 8xxx instructions + lda ins.w + and #$0f + asl a + tay + lda jumptable.op8, y + sta ins.ptr + lda jumptable.op8+1, y + sta ins.ptr+1 + bne execute + beq oINV ++ asl a + tay + lda jumptable.main, y + sta ins.ptr + lda jumptable.main+1, y + sta ins.ptr+1 + bne execute + ldy #0 +- lda jumptable.sparse+3, y + beq oINV + lda ins.opcode + cmp jumptable.sparse, y + bne + + lda ins.opcode+1 + and #$f0 + cmp jumptable.sparse+1, y + bne + + lda jumptable.sparse+2, y + sta ins.ptr + lda jumptable.sparse+3, y + sta ins.ptr+1 + bne execute + beq oINV ++ iny + iny + iny + iny + bne - +execute + ldx ins.x + ldy ins.y + jmp (ins.ptr) + .endproc + +FetchNext .macro + jmp C8Run.fetch + .endmacro + +oINV .proc + inc $d020 ; FIXME + jmp * + .endproc + +oNOP .proc + .FetchNext + .endproc + + ; 00E0 - CLS +oCLS .proc + jsr c8cls + .FetchNext + .endproc + + ; 00EE - RET +oRET .proc + lda reg.sp + asl a + tax + lda c8stack, x + sta reg.pc + lda c8stack+1, x + sta reg.pc+1 + dec reg.sp + ; FIXME: check stack boundaries + .FetchNext + .endproc + + ; 2nnn - CALL addr +oCALL .proc + inc reg.sp + ; FIXME: check stack boundaries + lda reg.sp + asl a + tax + lda reg.pc + sta c8stack, x + lda reg.pc+1 + sta c8stack+1, x + ; could fallthrough to oJP instead + lda ins.w + sta reg.pc + lda ins.w+1 + and #$0f + sta reg.pc+1 + .FetchNext + .endproc + + ; 1nnn - JP addr +oJP .proc + lda ins.w + sta reg.pc + stx reg.pc+1 + .FetchNext + .endproc + +skip .proc + clc + lda #2 + adc reg.pc + sta reg.pc + lda #0 + adc reg.pc+1 + sta reg.pc+1 + .FetchNext + .endproc + + ; 3xkk - SE Vx, byte +oSEK .proc + lda reg.v, x + cmp ins.w + beq skip + .FetchNext + .endproc + + ; 4xkk - SNE Vx, byte +oSNEK .proc + lda reg.v, x + cmp ins.w + bne skip + .FetchNext + .endproc + + ; 5xy0 - SE Vx, Vy +oSE .proc + lda reg.v, x + cmp reg.v, y + beq skip + .FetchNext + .endproc + + ; 6xkk - LD Vx, byte +oLDn .proc + lda ins.w + sta reg.v, x + .FetchNext + .endproc + + ; 7xkk - ADD Vx, byte +oADDn .proc + lda ins.w + clc + adc reg.v, x + sta reg.v, x + .FetchNext + .endproc + + ; 8xy0 - LD Vx, Vy +oLD .proc + lda reg.v, y + sta reg.v, x + .FetchNext + .endproc + + ; 8xy1 - OR Vx, Vy +oOR .proc + lda reg.v, y + ora reg.v, x + sta reg.v, x + .FetchNext + .endproc + + ; 8xy2 - AND Vx, Vy +oAND .proc + lda reg.v, y + and reg.v, x + sta reg.v, x + .FetchNext + .endproc + + ; 8xy3 - XOR Vx, Vy +oXOR .proc + lda reg.v, y + eor reg.v, x + sta reg.v, x + .FetchNext + .endproc + + ; 8xy4 - ADD Vx, Vy +oADD .proc + lda reg.v, y + clc + adc reg.v, x + sta reg.v, x + lda #0 + rol a + sta reg.v+$f + .FetchNext + .endproc + + ; 8xy5 - SUB Vx, Vy +oSUB .proc + lda reg.v, x + sec + sbc reg.v, y + sta reg.v, x + lda #0 + rol a + sta reg.v+$f + .FetchNext + .endproc + + ; 8xy6 - SHR Vx {, Vy} +oSHR .proc + lda #EF_SHIFTX + and eflags + beq _shifty + lda reg.v, x + lsr a + bpl + +_shifty + lda reg.v, y + lsr a + sta reg.v, y ++ sta reg.v, x + lda #0 + rol a + sta reg.v+$f + .FetchNext + .endproc + + ; 8xy7 - SUBN Vx, Vy +oSUBN .proc + lda reg.v, y + sec + sbc reg.v, x + sta reg.v, x + lda #0 + rol a + sta reg.v+$f + .FetchNext + .endproc + + ; 8xyE - SHL Vx {, Vy} +oSHL .proc + lda #EF_SHIFTX + and eflags + clc + beq _shifty + + lda reg.v, x + rol a + jmp + +_shifty + lda reg.v, y + rol a + sta reg.v, y ++ sta reg.v, x + lda #0 + rol a + sta reg.v+$f + .FetchNext + .endproc + + ; 9xy0 - SNE Vx, Vy +oSNE .proc + lda reg.v, x + cmp reg.v, y + bne skip + .FetchNext + .endproc + + ; Annn - LD I, addr +oLDI .proc + lda ins.w + sta reg.i + stx reg.i+1 + .FetchNext + .endproc + + ; Bnnn - JP V0, addr +oJPI .proc + lda reg.v + clc + adc ins.w + sta reg.pc + txa + adc #0 + sta reg.pc+1 + .FetchNext + .endproc + + ; Cxkk - RND Vx, byte +oRND .proc + jsr rand + and ins.w + sta reg.v, x + .FetchNext + .endproc + + ; Dxyn - DRW Vx, Vy, nibble +oDRW .proc + lda reg.v, y + and #%0001_1111 + asl a + asl a + asl a + sta startpos + lda reg.v, x + and #%0011_1111 + tax + and #%0000_0111 + sta bitshift + txa + lsr a + lsr a + lsr a + ora startpos + sta startpos + lda #0 + sta reg.v+$f + lda ins.w + and #%0000_1111 + beq done + sta ins.w + lda #1 + sta scrdirty + jsr regItozptr1 + ldy #0 +nextline + lda (zptr1), y + sta bitsl + lda #0 + sta bitsr + ldx bitshift + beq + +- lsr bitsl + ror bitsr + dex + bne - ++ ldx startpos + lda bitsl + and c8screen, x + beq + + lda #1 + sta reg.v+$f ++ lda bitsl + eor c8screen, x + sta c8screen, x + inx + beq done + txa + and #$7 + beq skipr + lda bitsr + and c8screen, x + beq + + lda #1 + sta reg.v+$f ++ lda bitsr + eor c8screen, x + sta c8screen, x +skipr lda #8 + clc + adc startpos + bcs done + sta startpos + iny + cpy ins.w + bmi nextline +done .FetchNext + + .section bss +startpos .byte ? +bitshift .byte ? +bitsl .byte ? +bitsr .byte ? + .endsection + + .endproc + + ; Ex9E - SKP Vx +oSKP .proc + jsr ReadKeyboard + bmi + + cmp reg.v, x + beq skip ++ .FetchNext + .endproc + + ; ExA1 - SKNP Vx +oSKNP .proc + jsr ReadKeyboard + bmi skip + cmp reg.v, x + bne skip + .FetchNext + .endproc + + ; Fx07 - LD Vx, DT +oLDxDT .proc + lda reg.dt + sta reg.v, x + .FetchNext + .endproc + + ; Fx0A - LD Vx, K +oLDK .proc + jsr ReadKeyboard + bpl + + sec + lda reg.pc + sbc #2 + sta reg.pc + lda reg.pc+1 + sbc #0 + sta reg.pc+1 + .FetchNext ++ sta reg.v, x + .FetchNext + .endproc + + ; Fx15 - LD DT, Vx +oLDDTx .proc + lda reg.v, x + sta reg.dt + .FetchNext + .endproc + + ; Fx18 - LD ST, Vxsnd_ +oLDSTx .proc + lda reg.v, x + sta reg.st + beq + + jsr SoundOn + .FetchNext ++ jsr SoundOff + .FetchNext + .endproc + + ; Fx1E - ADD I, Vx +oADDI .proc + lda reg.v, x + clc + adc reg.i + sta reg.i + lda #0 + adc reg.i+1 + sta reg.i+1 + .FetchNext + .endproc + + ; Fx29 - LD F, Vx +oLDF .proc + lda reg.v, x + asl a + asl a + clc + adc reg.v, x + sta reg.i + lda #0 + sta reg.i+1 + .FetchNext + .endproc + + ; Fx33 - LD B, Vx +oLDB .proc + jsr regItozptr1 + lda #0 + tay + sta (zptr1), y + iny + sta (zptr1), y + lda reg.v, x + sta zptr2 + ldx #8 + sed + ldy #1 +- asl zptr2 + lda (zptr1), y + adc (zptr1), y + sta (zptr1), y + dey + lda (zptr1), y + adc (zptr1), y + sta (zptr1), y + iny + dex + bne - + cld + ; y == 1 + ; now I -> 0A BC xx + ; we need I -> 0A 0B 0C + lda (zptr1), y + tax + and #$0f + iny + sta (zptr1), y + dey + txa + lsr a + lsr a + lsr a + lsr a + sta (zptr1), y + .FetchNext + .endproc + + ; Fx55 - LD [I], Vx +oLDIx .proc + jsr regItozptr1 + txa + tay +- lda reg.v, y + sta (zptr1), y + dey + bpl - + .FetchNext + .endproc + + ; Fx65 - LD Vx, [I] +oLDxI .proc + jsr regItozptr1 + txa + tay +- lda (zptr1), y + sta reg.v, y + dey + bpl - + .FetchNext + .endproc + +regItozptr1 .proc +ADDRMASK = C8RAMSIZE - 1 + clc + lda reg.i + .if (ADDRMASK & $00ff) != $00ff + and #ADDRMASK + adc #>C8RAM + sta zptr1+1 + rts + .endproc + +c8cls .proc + .FillMem c8screen, 0, size(c8screen) + lda #1 + sta scrdirty + rts + .endproc + +rand .proc + ; stir rng state and return next value in A + ; https://github.com/edrosten/8bit_rng/blob/master/rng-4261412736.c + ; unsigned char t = x ^ (x << 4); + ; x=y; + ; y=z; + ; z=a; + ; a = z ^ t ^ ( z >> 1) ^ (t << 1); + + lda rngst + asl a + asl a + asl a + asl a + eor rngst + sta rng_t1 + asl a + eor rng_t1 + sta rng_t1 ; t1 = (t << 1) ^ t + lda rngst+1 + sta rngst + lda rngst+2 + sta rngst+1 + lda rngst+3 + sta rngst+2 + lsr a + eor rngst+2 ; ra = ( z >> 1 ) ^ z + eor rng_t1 + sta rngst+3 + rts + .endproc + + .endsection code + + .section data +sprites .block + .byte $F0, $90, $90, $90, $F0 ; 0 + .byte $20, $60, $20, $20, $70 ; 1 + .byte $F0, $10, $F0, $80, $F0 ; 2 + .byte $F0, $10, $F0, $10, $F0 ; 3 + .byte $90, $90, $F0, $10, $10 ; 4 + .byte $F0, $80, $F0, $10, $F0 ; 5 + .byte $F0, $80, $F0, $90, $F0 ; 6 + .byte $F0, $10, $20, $40, $40 ; 7 + .byte $F0, $90, $F0, $90, $F0 ; 8 + .byte $F0, $90, $F0, $10, $F0 ; 9 + .byte $F0, $90, $F0, $90, $90 ; a + .byte $E0, $90, $E0, $90, $E0 ; b + .byte $F0, $80, $80, $80, $F0 ; c + .byte $E0, $90, $90, $90, $E0 ; d + .byte $F0, $80, $F0, $80, $F0 ; e + .byte $F0, $80, $F0, $80, $80 ; f + .bend + +eflags .byte 0 + +jumptable .block +ops = [0, oJP, oCALL, oSEK, oSNEK, oSE, oLDn, oADDn, oINV, oSNE, oLDI, oJPI, oRND, oDRW, 0, 0] +ops8 = [oLD, oOR, oAND, oXOR, oADD, oSUB, oSHR, oSUBN, oINV, oINV, oINV, oINV, oINV, oINV, oSHL, oINV] +main .addr ops +op8 .addr ops8 +sparse .word $00e0, oCLS + .word $00ee, oRET + .word $e09e, oSKP + .word $e0a1, oSKNP + .word $f007, oLDxDT + .word $f00a, oLDK + .word $f015, oLDDTx + .word $f018, oLDSTx + .word $f01e, oADDI + .word $f029, oLDF + .word $f033, oLDB + .word $f055, oLDIx + .word $f065, oLDxI + .word 0, 0 + .endblock + + .if EMBEDSAMPLE +samplecode .block + ; .binary "samples/ibmlogo.ch8" + ; .binary "samples/tetris.ch8" + ; .binary "samples/lunarlander.ch8" + ; .binary "diags/keypad.ch8" + .binary "samples/opcodes.ch8" + ; .binary "diags/sound.ch8" + .endblock + .endif + + .endsection data + +; vim: syntax=64tass diff --git a/chipty5-64.asm b/chipty5-64.asm new file mode 100644 index 0000000..aa2c98f --- /dev/null +++ b/chipty5-64.asm @@ -0,0 +1,230 @@ +C8RAMSIZE = 4096 + .virtual $c000 +C8RAM .fill C8START +C8ENTRY .fill C8RAMSIZE - C8START +c8ramend = *-1 + .endvirtual + +ZP_START = $61 + +.BasicStub MainEntry, 2021 + + .section code + +MainEntry .proc + ;lda #EF_REGS + lda #0 + sta eflags + + jsr InitRandom + jsr VideoInit + jsr SoundInit + jsr ClearScreen + jsr ShowTitle + jsr C8Reset + jsr SetupIRQ + jsr C8Run + rts + .endproc + +SetupIRQ .proc + lda #64 + sta prevkey + sei + lda CINV + sta sysirq + lda CINV+1 + sta sysirq+1 + lda #handler + sta CINV+1 + cli + rts +handler + lda SFDX + tax + cmp prevkey + beq dotick + cmp #3 ; F7: reset + bne + + lda #EF_RESET + ora eflags + sta eflags + jmp done ++ txa + cmp #6 ; F5: Pause + bne + + lda #EF_PAUSE + eor eflags + sta eflags + jmp done ++ txa + cmp #53 ; =: Registers + bne + + lda #EF_REGS + eor eflags + sta eflags + jmp done ++ txa + cmp #43 ; -: Shift behaviour + bne + + lda #EF_SHIFTX + eor eflags + sta eflags + jmp done ++ txa + cmp #55 ; /: Load + bne + + lda #EF_LOAD + ora eflags + sta eflags + ; jmp done ++ +done stx prevkey +dotick jsr Tick + jmp (sysirq) + + .section bss +sysirq .word ? +prevkey .byte ? + .endsection bss + + .endproc + +RestoreIRQ .proc + sei + lda SetupIRQ.sysirq + sta CINV + lda SetupIRQ.sysirq+1 + sta CINV+1 + cli + rts + .endproc + +InitRandom .proc + ldx #0 +- lda TIME, x + sta rngst, x + inx + cpx #3 + bne - + lda io.vic2.raster + sta rngst+3 + rts + .endproc + +ClearScreen .proc + lda #0 + sta io.vic2.ec + sta io.vic2.b0c + lda #'{green}' + jsr CHROUT + lda #'{clear}' + jsr CHROUT + rts + .endproc + +ReadKeyboard .proc + lda SFDX + cmp #64 + bne + +nokey + lda #$ff + rts + ++ ldy #0 +- cmp kbdcodes, y + beq + + cpy #size(kbdcodes) + beq nokey + iny + bne - ++ tya + rts + .endproc + +GetVBlank .proc + sec + ; Clear carry flag if retracing + lda #200 + cmp io.vic2.raster + rts + .endproc + +SoundInit .proc +FREQ = io.sid_freq(880) +DUTY = io.sid_duty(0.5) + lda #0 + sta io.sid.voice1.ctrl + sta io.sid.voice2.ctrl + sta io.sid.voice3.ctrl + sta io.sid.voice1.ad + lda #$f0 + sta io.sid.voice1.sr + lda #$0f + sta io.sid.volume + lda #DUTY + sta io.sid.voice1.duty+1 + lda #FREQ + sta io.sid.voice1.freq+1 + lda #io.SID_CTRL_PULSE + sta io.sid.voice1.ctrl + rts + .endproc + +SoundOn .proc + lda #io.SID_CTRL_PULSE|io.SID_CTRL_GATE + sta io.sid.voice1.ctrl + rts + .endproc + +SoundOff .proc + lda #io.SID_CTRL_PULSE + sta io.sid.voice1.ctrl + rts + .endproc + +InputFileName .proc + jsr RestoreIRQ + ldx #ROW_FILENAME + ldy #0 + sty ch8filenamelen + sty NDX + clc + jsr PLOT + lda #prompt + jsr STROUT + ldy #0 +- lda #0 + sta ch8filename, y + jsr CHRIN + cmp #13 + beq + + sta ch8filename, y + iny + jmp - ++ sty ch8filenamelen + ldx #ROW_FILENAME + jsr ClearLine + jsr SetupIRQ + rts + + .section data +prompt .null "file name: " + .endsection data + .endproc + + + .endsection code + + .section data +kbdcodes .byte 56, 59, 8, 11, 62, 9, 14, 17, 10, 13, 18, 21, 12, 23, 20, 31 + .endsection data + +; vim: syntax=64tass \ No newline at end of file diff --git a/chipty5-pet40.asm b/chipty5-pet40.asm new file mode 100644 index 0000000..c14ae56 --- /dev/null +++ b/chipty5-pet40.asm @@ -0,0 +1,237 @@ +C8RAMSIZE = 4096 + .virtual $2000 +C8RAM .fill C8START +C8ENTRY .fill C8RAMSIZE - C8START +c8ramend = *-1 + .endvirtual + +IS_PET = true + +ZP_START = $54 + +.BasicStub MainEntry, 2021 + + .section code + +MainEntry .proc + ;lda #EF_REGS + lda #0 + sta eflags + + jsr InitRandom + jsr ClearScreen + jsr ShowTitle + jsr C8Reset + jsr SoundInit + jsr SetupIRQ + jsr C8Run + rts + .endproc + +NOKEY = 255 + +SetupIRQ .proc + lda #NOKEY + sta prevkey + sei + lda CINV + sta sysirq + lda CINV+1 + sta sysirq+1 + lda #handler + sta CINV+1 + cli + rts +handler + lda LSTX + tax + cmp prevkey + beq dotick + cmp #20 ; backspace: reset + bne + + lda #EF_RESET + ora eflags + sta eflags + jmp done ++ txa + cmp #'.' ; '.'': Pause + bne + + lda #EF_PAUSE + eor eflags + sta eflags + jmp done ++ txa + cmp #'=' ; =: Registers + bne + + lda #EF_REGS + eor eflags + sta eflags + jmp done ++ txa + cmp #"-" ; -: Shift behaviour + bne + + lda #EF_SHIFTX + eor eflags + sta eflags + jmp done ++ txa + cmp #'/' ; '/': Load + bne + + lda #EF_LOAD + ora eflags + sta eflags + jmp done ++ +done stx prevkey +dotick jsr Tick + jmp (sysirq) + + .section bss +sysirq .word ? +prevkey .byte ? + .endsection bss + + .endproc + +RestoreIRQ .proc + sei + lda SetupIRQ.sysirq + sta CINV + lda SetupIRQ.sysirq+1 + sta CINV+1 + cli + rts + .endproc + +InitRandom .proc + ldx #0 +- lda TIME, x + sta rngst, x + inx + cpx #3 + bne - + ;lda io.vic2.raster + ;sta rngst+3 + rts + .endproc + +ClearScreen .proc + lda #'{clear}' + jsr CHROUT + rts + .endproc + +ReadKeyboard .proc + lda LSTX + cmp #NOKEY + bne + +nokey + lda #$ff + rts + ++ ldy #0 +- cmp kbdcodes, y + beq + + cpy #size(kbdcodes) + beq nokey + iny + bne - ++ tya + rts + .endproc + +GetVBlank .proc + ; Clear carry flag if retracing + ; FIXME + clc + rts + + lda #io.CRTC_VBLANK + bit io.crtc.ctrl + bne + + sec + rts ++ clc + rts + .endproc + +SoundInit .proc + lda #io.VIA_SR_OUT_T2_FR + sta io.via.acr + lda #0 + sta io.via.t2c + lda #22 + sta io.via.sr + rts + .endproc + +SoundOn .proc + lda #211 + sta io.via.t2c + rts + .endproc + +SoundOff .proc + lda #0 + sta io.via.t2c + rts + .endproc + + +InputFileName .proc + jsr RestoreIRQ + ldy #0 + sty ch8filenamelen + sty NDX + lda #'{home}' + jsr CHROUT + ldx #ROW_FILENAME + lda #'{down}' +- jsr CHROUT + dex + bne - + ldx #ROW_FILENAME + ldy #0 + jsr myPLOT + lda #prompt + jsr mySTROUT + lda #ROW_FILENAME + sta TBLX + lda #size(prompt) + sta PNTR + jsr $e07f + ldy #0 +- lda #0 + sta ch8filename, y + jsr CHRIN + cmp #13 + beq + + sta ch8filename, y + iny + jmp - ++ sty ch8filenamelen + ldx #ROW_FILENAME + jsr ClearLine + jsr SetupIRQ + rts + + .section data + .enc "screen" +prompt .null "file name: " + .enc "none" + .endsection data + .endproc + + + + .endsection code + + .section data +; kbdcodes .byte 56, 59, 8, 11, 62, 9, 14, 17, 10, 13, 18, 21, 12, 23, 20, 31 +kbdcodes .text "1234qwerasdfzxcv" + .endsection data + +; vim: syntax=64tass \ No newline at end of file diff --git a/chipty5-plus4.asm b/chipty5-plus4.asm new file mode 100644 index 0000000..ec8834e --- /dev/null +++ b/chipty5-plus4.asm @@ -0,0 +1,230 @@ +C8RAMSIZE = 4096 + .virtual $3000 +C8RAM .fill C8START +C8ENTRY .fill C8RAMSIZE - C8START +c8ramend = *-1 + .endvirtual + +ZP_START = $d0 + +.BasicStub MainEntry, 2021 + + .section code + +MainEntry .proc + ;lda #EF_REGS + lda #0 + sta eflags + + jsr InitRandom + jsr VideoInit + jsr SoundInit + jsr ClearScreen + jsr ShowTitle + jsr C8Reset + jsr SetupIRQ + jsr C8Run + rts + .endproc + +SetupIRQ .proc + lda #64 + sta prevkey + sei + lda CINV + sta sysirq + lda CINV+1 + sta sysirq+1 + lda #handler + sta CINV+1 + cli + rts +handler + lda SFDX + tax + cmp prevkey + beq dotick + cmp #3 ; F7: reset + bne + + lda #EF_RESET + ora eflags + sta eflags + jmp done ++ txa + cmp #6 ; F5: Pause + bne + + lda #EF_PAUSE + eor eflags + sta eflags + jmp done ++ txa + cmp #53 ; =: Registers + bne + + lda #EF_REGS + eor eflags + sta eflags + jmp done ++ txa + cmp #46 ; -: Shift behaviour + bne + + lda #EF_SHIFTX + eor eflags + sta eflags + jmp done ++ txa + cmp #55 ; /: Load + bne + + lda #EF_LOAD + ora eflags + sta eflags + ; jmp done ++ +done stx prevkey +dotick jsr Tick + jmp (sysirq) + + .section bss +sysirq .word ? +prevkey .byte ? + .endsection bss + + .endproc + +RestoreIRQ .proc + sei + lda SetupIRQ.sysirq + sta CINV + lda SetupIRQ.sysirq+1 + sta CINV+1 + cli + rts + .endproc + +InitRandom .proc + ldx #0 +- lda TIME, x + sta rngst, x + inx + cpx #3 + bne - + lda io.ted.rasterline_lo + sta rngst+3 + lda io.ted.rastercolumn + eor rngst+1 + sta rngst+1 + rts + .endproc + +ClearScreen .proc + lda #0 + sta io.ted.bgcolor + sta io.ted.bordercolor + lda #'{green}' + jsr CHROUT + lda #'{clear}' + jsr CHROUT + rts + .endproc + +ReadKeyboard .proc + lda SFDX + cmp #64 + bne + +nokey + lda #$ff + rts + ++ ldy #0 +- cmp kbdcodes, y + beq + + cpy #size(kbdcodes) + beq nokey + iny + bne - ++ tya + rts + .endproc + +GetVBlank .proc + sec + lda #200 + cmp io.ted.rasterline_lo + rts + .endproc + +SoundInit .proc +FREQ = io.ted_freq(880) + lda #$0f + sta io.ted.snd_ctrl + lda #FREQ + ; ora io.ted.misc + ; sta io.ted.misc + lda io.ted.misc + and #%1111_1100 + ora #>FREQ + sta io.ted.misc + rts + .endproc + +SoundOn .proc + lda #$10 + ora io.ted.snd_ctrl + sta io.ted.snd_ctrl + rts + .endproc + +SoundOff .proc + lda #~$10 + and io.ted.snd_ctrl + sta io.ted.snd_ctrl + rts + .endproc + +InputFileName .proc + jsr RestoreIRQ + ldx #ROW_FILENAME + ldy #0 + sty ch8filenamelen + sty NDX + clc + jsr myPLOT + lda #prompt + jsr mySTROUT + ldx #ROW_FILENAME + ldy #size(prompt) + clc + jsr PLOT + ldy #0 +- lda #0 + sta ch8filename, y + jsr CHRIN + cmp #13 + beq + + sta ch8filename, y + iny + jmp - ++ sty ch8filenamelen + ldx #ROW_FILENAME + jsr ClearLine + jsr SetupIRQ + rts + + .section data + .enc "screen" +prompt .null "file name: " + .enc "none" + .endsection data + .endproc + + .endsection code + + .section data +kbdcodes .byte 56, 59, 8, 11, 62, 9, 14, 17, 10, 13, 18, 21, 12, 23, 20, 31 + .endsection data + +; vim: syntax=64tass \ No newline at end of file diff --git a/crtc.asm b/crtc.asm new file mode 100644 index 0000000..065865c --- /dev/null +++ b/crtc.asm @@ -0,0 +1,15 @@ +; +; 6545/6845 (CRTC) registers +; + + .virtual +_crtc .struct +ctrl .byte ? +data .byte ? + .endstruct + .endvirtual + +CRTC_LPEN = %0100_0000 +CRTC_VBLANK = %0010_0000 + +; vim: syntax=64tass diff --git a/diags/grid.ch8asm b/diags/grid.ch8asm new file mode 100644 index 0000000..bb4b398 --- /dev/null +++ b/diags/grid.ch8asm @@ -0,0 +1,16 @@ + LD I, .corner + LD V1, 0 +.yloop LD V0, 0 +.xloop DRW V0, V1, 8 + ADD V0, 08 + SE V0, 40 + JP .xloop + ADD V1, 08 + SE V1, 20 + JP .yloop +.halt JP .halt + +.corner DATA ff80 + DATA 8080 + DATA 8080 + DATA 8080 diff --git a/diags/keypad.ch8asm b/diags/keypad.ch8asm new file mode 100644 index 0000000..715b8ef --- /dev/null +++ b/diags/keypad.ch8asm @@ -0,0 +1,9 @@ + + LD V1, 00 +.loop LD V0, K + LD F, V0 + DRW V1, V1, 5 +.down SKNP V0 + JP .down + DRW V1, V1, 5 + JP .loop diff --git a/diags/sound.ch8asm b/diags/sound.ch8asm new file mode 100644 index 0000000..cf71c0c --- /dev/null +++ b/diags/sound.ch8asm @@ -0,0 +1,4 @@ + LD V0, 78 + LD ST, V0 +.loop JP .loop + diff --git a/display-pet40.asm b/display-pet40.asm new file mode 100644 index 0000000..8fc09eb --- /dev/null +++ b/display-pet40.asm @@ -0,0 +1,349 @@ +; +; This is the video output driver for 40 column PETSCII machines +; Each 2x2 pixel block is mapped to a single PETSCII character +; + +SCREEN_COLS = 40 +SCREEN_ROWS = 25 + +ROW_TILE = 0 +ROW_REGS = 1 +ROW_FLAGS = 2 +ROW_FILENAME = 3 + + +VIDEO_TOP = (SCREEN_ROWS-16) +VIDEO_LEFT = (SCREEN_COLS - (64/2)) / 2 + +VIDEO_START = SCREEN_RAM + SCREEN_COLS * VIDEO_TOP + VIDEO_LEFT + +; 00 00 00 00 01 01 01 01 10 10 10 10 11 11 11 11 +; 00 01 10 11 00 01 10 11 00 01 10 11 00 01 10 11 +petpixels = [ $20, $6c, $7b, $62, $7c, $e1, $ff, $fe, $7e, $7f, $61, $fc, $e2, $fb, $ec, $a0 ] + + .section data +qpix .byte petpixels + .endsection data + + .section code + +VideoInit .proc + rts + .endproc + +VideoDraw .proc + ldx #0 + stx scrdirty + lda #VIDEO_START + sta zptr1+1 +- lda c8screen, x + and #%11_00_11_00 + sta zptr2 + lda c8screen+8, x + and #%11_00_11_00 + lsr a + lsr a + ora zptr2 + sta zptr2 + lda c8screen, x + and #%00_11_00_11 + asl a + asl a + sta zptr2+1 + lda c8screen+8, x + and #%00_11_00_11 + ora zptr2+1 + sta zptr2+1 + and #$0f + tay + lda qpix, y + ldy #3 + sta (zptr1), y + lda zptr2+1 + lsr a + lsr a + lsr a + lsr a + tay + lda qpix, y + ldy #1 + sta (zptr1), y + lda zptr2 + and #$0f + tay + lda qpix, y + ldy #2 + sta (zptr1), y + lda zptr2 + lsr a + lsr a + lsr a + lsr a + tay + lda qpix, y + ldy #0 + sta (zptr1), y + lda #4 + clc + adc zptr1 + sta zptr1 + tya + adc zptr1+1 + sta zptr1+1 + inx + txa + and #7 + bne - + lda #(SCREEN_COLS-32) + clc + adc zptr1 + sta zptr1 + tya + adc zptr1+1 + sta zptr1+1 + txa + clc + adc #8 ; skip every other row since we are processing two rows at a time + tax + beq + + jmp - ++ rts + .endproc + +ShowFlags .proc + ldx #0 + lda eflags + sta tmpflags +- rol tmpflags + bcc + + lda flags, x + bne next ++ lda #' ' +next sta SCREEN_RAM+SCREEN_COLS*(ROW_FLAGS+1)-8, x + inx + cpx #8 + bne - + rts + .section data + .enc "screen" +flags .text "pltr321s" + .enc "none" + .endsection data + .section bss +tmpflags .byte ? + .endsection bss + .endproc + +ClearLine .proc + ldy #0 + clc + jsr myPLOT + lda #' ' + ldx #SCREEN_COLS +- jsr myCHROUT + dex + bne - + rts + .endproc + +ShowRegisters .proc + lda #0 + ldx #ROW_REGS + tay + clc + jsr myPLOT + ldx #0 +- txa + pha + lda reg.v, x + jsr HexByteOut + pla + tax + inx + cmp #$0f + bmi - + lda reg.i+1 + jsr HexByteOut + lda reg.i + jsr HexByteOut + lda reg.pc+1 + jsr HexByteOut + lda reg.pc + jsr HexByteOut + rts + .endproc + +ShowTimers .proc + .enc "screen" + lda #'d' + ldx reg.dt + bne + + clc + adc #' '-'d' ++ sta SCREEN_RAM+SCREEN_COLS*ROW_FLAGS + lda #'s' + ldx reg.st + bne + + clc + adc #' '-'s' ++ sta SCREEN_RAM+SCREEN_COLS*ROW_FLAGS+1 + rts + .enc "none" + .endproc + +HexByteOut .proc + tay + lsr a + lsr a + lsr a + lsr a + tax + lda hexdigits, x + jsr myCHROUT + tya + and #$0f + tax + lda hexdigits, x + jsr myCHROUT + rts + .section data + .enc "screen" +hexdigits .text "0123456789abcdef" + .enc "none" + .endsection data + + .endproc + +myPLOT .proc + pha + txa + ldx #0 + stx cursorpos+1 + asl a + asl a + asl a + sta cursorpos + asl a + rol cursorpos+1 + asl a + rol cursorpos+1 + clc + adc cursorpos + sta cursorpos + clc + tya + adc cursorpos + sta cursorpos + lda #>SCREEN_RAM + adc cursorpos+1 + sta cursorpos+1 + pla + rts + .endproc + +myCHROUT .proc + pha + sta chr + tya + pha + ldy #0 + lda chr + sta (cursorpos), y + inc cursorpos + bne + + inc cursorpos+1 ++ pla + tay + pla + rts +chr .byte ? + .endproc + +mySTROUT .proc + sta zptr1 + sty zptr1+1 + ldy #0 +- lda (zptr1), y + beq + + sta (cursorpos), y + iny + bne - + inc cursorpos+1 + rts ++ tya + clc + adc cursorpos + sta cursorpos + lda #0 + adc cursorpos+1 + sta cursorpos+1 + rts + .endproc + +HeartBeat .proc + lda step + clc + adc #1 + and #size(glyphs)-1 + sta step + tax + lda glyphs, x + sta SCREEN_RAM+SCREEN_COLS-1 + jsr ShowTimers + + lda eflags + and #EF_REGS + beq + + jsr ShowRegisters ++ lda eflags + and #EF_LOAD + beq + + nop ++ lda eflags + eor preveflags + beq + + jsr ShowFlags + lda eflags + eor preveflags + and #EF_REGS + beq + + ldx #ROW_REGS + jsr ClearLine ++ lda eflags + sta preveflags + rts + + .section data +glyphs .byte $7b, $7e, $7c, $6c + .endsection data + .section bss +step .byte ? +preveflags .byte ? + .endsection + .endproc + +ShowTitle .proc + lda #0 + tax + tay + jsr myPLOT + ldy #>title + lda # 0 + .align \align + .endif + .endsection + .endmacro + +FillMem .macro ptr, value, sz + .for blocksz := 256, ((\sz) % blocksz) > 0, blocksz -= 1 + .endfor + blocks = (\sz) / blocksz + + lda #\value + .if (\value) != 0 + ldx #0 + .else + tax + .endif +- .for b := 0, b < blocks, b += 1 + sta (\ptr) + (b * blocksz), x + .endfor + inx + .if blocksz != 256 + cpx #blocksz + .endif + bne - ++ + .endmacro + +CopyMem .macro src, dst, sz + .for blocksz := 256, ((\sz) % blocksz) > 0, blocksz -= 1 + .endfor + blocks = (\sz) / blocksz + + ldx #0 +- .for b := 0, b < blocks, b += 1 + lda (\src) + (b * blocksz), x + sta (\dst) + (b * blocksz), x + .endfor + inx + .if blocksz != 256 + cpx #blocksz + .endif + bne - ++ .endmacro + +; *=$c000 +; +; .FillMem 1024, 0, 10000 +; rts + +; vim: syntax=64tass diff --git a/pet.asm b/pet.asm new file mode 100644 index 0000000..78307e8 --- /dev/null +++ b/pet.asm @@ -0,0 +1,195 @@ +; +; Commodore PET specific constants and memory addresses +; + + .proff + + .cpu "6502" + + +io .namespace + + .include "via.asm" + .include "crtc.asm" + + .virtual $e840 +via .dstruct _via + .endvirtual + + .virtual $e880 +crtc .dstruct _crtc + .endvirtual + + .endnamespace + +BASIC_START = $0401 +BTOK_SYS = $9e +SCREEN_RAM = $8000 + + + +USRPOK = $0000 ; USR Function Jump Instr (4C) +USRADD = $0001 ; USR Address Low Byte / High Byte +CHARAC = $0003 ; Search Character +ENDCHR = $0004 ; Flag: Scan for Quote at End of String +COUNT = $0005 ; Input Buffer Pointer / No. of Subscripts +DIMFLG = $0006 ; Flag: Default Array DiMension / array name +VAUYP = $0007 ; Data Type: $FF = String, $00 = Numeric +INTFLG = $0008 ; Data Type: $80 = Integer, $00 = Floating +GARBFL = $0009 ; Flag: DATA scan/LlST quote/Garbage Coll +SUBFLG = $000a ; Flag: Subscript Ref / User Function Call +INPFLG = $000b ; Flag: $00 = INPUT, $40 = GET, $98 = READ +TANSGN = $000c ; Flag TAN sign / Comparison Result +LINNUM = $0011 ; Temp: Integer Value +TEMPPT = $0013 ; Pointer Temporary String +LASTPT = $0014 ; Last Temp String Address +TEMPST = $0016 ; Stack for Temporary Strings +INDEX = $001f ; Utility Pointer Area +RESHO = $0023 ; Floating-Point Product of Multiply +TXTTAB = $0028 ; Pointer: Start of BASIC Text +VARTAB = $002a ; Pointer: Start of BASIC Variables +ARYTAB = $002c ; Pointer: Start of BASIC Arrays +STREND = $002e ; Pointer End of BASIC Arrays (+1) +FRETOP = $0030 ; Pointer: Bottom of String Storage +FRESPC = $0032 ; Utility String Pointer +MEMSIZ = $0034 ; Pointer: Highest Address Used by BASIC +CURLIN = $0036 ; Current BASIC Line Number +OLDLIN = $0038 ; Previous BASIC Line Number +OLDTXT = $003a ; Pointer: BASIC Statement for CONT +DATLIN = $003c ; Current DATA Line Number +DATPTR = $003e ; Pointer: Current DATA Item Address +INPPTR = $0040 ; Vector: INPUT Routine +VARNAM = $0042 ; Current BASIC Variable Name +VARPNT = $0044 ; Pointer: Current BASIC Variable Data +FORPNT = $0046 ; Pointer: Index Variable for FOR/NEXT +TEMPF1 = $0054 ; Temporary storage for FLPT value. +TEMPF2 = $0059 ; Temporary storage for FLPT value. +FACEXP = $005e ; Floating-Point Accumulator #1: Exponent +FACHO = $005f ; Floating Accum. #1: Mantissa +FACSGN = $0063 ; Floating Accum. #1: Sign +SGNFLG = $0064 ; Pointer: Series Evaluation Constant Pointer +BITS = $0065 ; Floating -accum. #1: Overflow Digit +ARGEXP = $0066 ; Floating-Point Accumulator #2: Exponent +ARGHO = $0067 ; Floating Accum. #2: Mantissa +ARGSGN = $006b ; Floating Accum. #2: Sign +ARISGN = $006c ; Sign Comparison Result: Accum. # 1 vs #2 +FACOV = $006d ; Floating Accum. #1. Low-Order (Rounding) +FBUFPT = $006e ; Pointer: Cassette Buffer +CHRGET = $0070 ; Subroutine: Get Next Byte of BASIC Text +CHRGOT = $0076 ; Entry to Get Same Byte of Text Again +TXTPTR = $0077 ; Pointer: Current Byte of BASIC Text +RNDX = $0088 ; Floating RND Function Seed Value +TIME = $008d ; Real-Time Jiffy Clock (approx) 1/60 Sec +CINV = $0090 ; Vector: Hardware Interrupt +CBINV = $0092 ; Vector: BRK Instr. Interrupt +NMINV = $0094 ; Vector: Non-Maskable Interrupt +STATUS = $0096 ; Kernal I/O Status Word: ST +LSTX = $0097 ; Current Key Pressed: 255 = No Key +SFDX = $0098 ; Flag: Print Shifted Chars. +STKEY = $009b ; Flag: STOP key / RVS key +SVXT = $009c ; Timing Constant for Tape +VERCK = $009d ; Flag: 0 = Load, 1 = Verify (Kernel) +NDX = $009e ; No. of Chars. in Keyboard Buffer (Queue) +RVS = $009f ; Flag: Print Reverse Chars. -1=Yes, 0=No Used +C3PO = $00a0 ; Flag: Serial Bus-Output Char. Buffered +INDX = $00a1 ; Pointer: End of Logical Line for INPUT +LXSP = $00a3 ; Cursor Y-X Pos. at Start of INPUT +BSOUR = $00a5 ; Buffered Character for IEEE Bus +BLNSW = $00a7 ; Cursor Blink enable: 0 = Flash Cursor +BLNCT = $00a8 ; Timer: Countdown to Toggle Cursor +GDBLN = $00a9 ; Character Under Cursor +BLNON = $00aa ; Flag: Last Cursor Blink On/Off +CRSW = $00ac ; Flag: INPUT or GET from Keyboard +LDTND = $00ae ; No. of Open Files / Index to File Table +DFLTN = $00af ; Default Input Device (0) +DFLTO = $00b0 ; Default Output (CMD) Device (3) +PRTY = $00b1 ; Tape Character Parity +DPSW = $00b2 ; Flag: Tape Byte-Received +BUFPNT = $00bb ; Pointer: Tape I/O Buffer #1 +INBIT = $00bd ; Cassette Temp (64#00A7) +BITCI = $00be ; Cassette Temp (64#00A8) +RINONE = $00bf ; RS-232 Flag: Check for Start Bit (64#00A9) +FNMIDX = $00c0 ; Index to Cassette File name/Header ID for Tape write. +PTR1 = $00c0 ; Tape Pass 1 Error Log +PTR2 = $00c1 ; Tape Pass 2 Error Log +RIDATA = $00c2 ; Cassette Temp (64#00AA) read flags: 0=scan, 1-15=count, $40=load, $80=end of tape marker +RIPRTY = $00c3 ; Cassette Short Cnt (64#00AB): counter of seconds before tape write / checksum +PNT = $00c4 ; Pointer: Current Screen Line Address +PNTR = $00c6 ; Cursor Column on Current Line +SAL = $00c7 ; Pointer: Tape Buffer/ Screen Scrolling +EAL = $00c9 ; Tape End Addresses/End of Program +CMP0 = $00cb ; Tape Timing Constants +QTSW = $00cd ; Flag: Editor in Quote Mode, $00 = NO +BITTS = $00ce ; Cassette Temp (64#00B4): Tape read timer flag +FNLEN = $00d1 ; Length of Current File Name +LA = $00d2 ; Current Logical File Number +SA = $00d3 ; Current Secondary Address +FA = $00d4 ; Current Device Number +LNMX = $00d5 ; Physical Screen Line Length +TAPE1 = $00d6 ; Pointer: Start of Tape Buffer +TBLX = $00d8 ; Current Cursor Physical Line Number +DATAX = $00d9 ; Current Character to Print +FNADR = $00da ; Pointer: Current File Name +INSRT = $00dc ; Flag: Insert Mode, >0 = # INSTs +ROPRTY = $00dd ; Cassette Temp +FSBLK = $00de ; Cassette Read / Write Block Count +MYCH = $00df ; Serial Word Buffer +LDTB1 = $00e0 ; 3+4.40: Screen Line Link Table / Editor Temps +SCTOP = $00e0 ; 4.80: first line of window +SCBOT = $00e1 ; 4.80: last line of window +SCLF = $00e2 ; 4.80: first column of window +XMAX = $00e3 ; 4.80: Size of Keyboard Buffer +;XMAX = $03eb ; 4.40 +RPTFLG = $00e4 ; 4.80: Flag: REPEAT Key Used, $80 = Repeat $40 = disable +;RPTFLG = $03ee ; 4.40 +KOUNT = $00e5 ; 4.80: Repeat Speed Counter +;KOUNT = $03ea ; 4.40 +DELAY = $00e6 ; 230 4.80: Repeat Delay Counter +;DELAY = $03e9 ; 4.40 +CAS1 = $00f9 ; Tape Motor Interlock #1 +CAS2 = $00fa ; Tape Motor Interlock #2 +STAL = $00fb ; I/O Start Address +MEMUSS = $00fd ; Tape Load Temps +BAD = $0100 ; Tape Input Error Log +BUF = $0200 ; System INPUT Buffer +LAT = $0251 ; KERNAL Table: Active Logical File No's. +FAT = $025b ; KERNAL Table: Device No. for Each File +SAT = $0265 ; KERNAL Table: Second Address Each File +KEYD = $0270 ; Keyboard Buffer Queue (FIFO) +TBUFFR = $027a ; Tape I/O Buffer #1 +;TBUFFR = $033a ; Tape I/O Buffer #2 +;DELAY = $03e9 ; 4.40 +;KOUNT = $03ea ; 4.40 +;XMAX = $03eb ; 4.40 +;RPTFLG = $03ee ; 4.40 +TIMOUT = $03fc ; 4: Flag: Kernal Variable for IEEE Timeout + +; Kernel + +; CHKIN = $ffc6 +; CHKOUT = $ffc9 +; CHRIN = $ffcf +; CHROUT = $ffd2 +; CLALL = $ffe7 +; CLOSE = $ffc3 +; CLRCHN = $ffcc +; CSYS = $ffde +; CVERF = $ffdb +; GETIN = $ffe4 +; LOAD = $ffd5 +; OPEN = $ffc0 +; SAVE = $ffd0 +; STOP = $ffe1 +; UDTIM = $ffea + +;CONSTANTS FROM PET BASIC 4.0 +CLRCHN =$FFCC ;CLOSE I/O CHANNELS +CHKIN =$FFC6 ;OPEN INPUT CHANNEL +CHRIN =$FFCF ;INPUT SOURCE BYTE +CHROUT =$FFD2 ;OUTPUT CHARACTER TO CHAN +CLOSE =$F2E2 ;CLOSE FILE .A +OPEN =$F563 ;OPEN FILE LA,FA,SA + + .pron + +; vim: syntax=64tass \ No newline at end of file diff --git a/plus4.asm b/plus4.asm new file mode 100644 index 0000000..760077b --- /dev/null +++ b/plus4.asm @@ -0,0 +1,585 @@ +; +; Commodore Plus 4 specific constants and memory addresses +; + .proff + + .cpu "6502" + +io .namespace + + .include "ted.asm" + + .virtual $ff00 +ted .dstruct _ted + .endvirtual + + .endnamespace + +BASIC_START = $1001 +BTOK_SYS = $9e +SCREEN_RAM = $0c00 + +; =========================================================================== + +PDIR = $0000 ; 7501 on-chip data-direction register +PORT = $0001 ; 7501 on-chip 8-bit Input/Output register +SRCHTK = $0002 ; Token 'search' looks for (run-time stack) +ZPVEC1 = $0003 ; Temp (renumber) +ZPVEC2 = $0005 ; Temp (renumber) +CHARAC = $0007 ; Search character +ENDCHR = $0008 ; Flag: scan for quote at end of string +TRMPOS = $0009 ; Screen column from last TAB +VERCK = $000A ; Flag: 0 = load 1 - verify +COUNT = $000B ; Input buffer pointer / No. of subsctipts +DIMFLG = $000C ; Flag: Default Array DIMension +VALTYP = $000D ; Data type: $FF = string $00 = numeric +INTFLG = $000E ; Data type: $80 = integer, $00 = floating +DORES = $000F ; Flag: DATA scan/LIST quote/garbage coll +SUBFLG = $0010 ; Flag: subscript ref / user function coll +INPFLG = $0011 ; Flag: $00 = INPUT, $43 = GET, $98 = READ +TANSGN = $0012 ; Flag TAN siqn / comparison result +CHANNL = $0013 ; Flag: INPUT prompt +LINNUM = $0014 ; Temp: integer value +TEMPPT = $0016 ; Pointer: temporary string stack +LASTPT = $0317 ; Last temp string address +TEMPST = $0019 ; Stack for temporary strings +INDEX1 = $0022 ; Utility pointer area +INDEX2 = $0024 ; Utility pointer area +RESHO = $0026 ; +RESMOH = $0027 ; +RESMO = $0028 ; +RESLO = $0029 ; +TXTTAB = $002B ; Pointer: start of BASIC text +VARTAB = $002D ; Pointer: start of BASIC variables +ARYTAB = $002E ; Pointer: start of BASIC arrays +STREND = $0031 ; Pointer: end of BASIC arrays (+1) +FRFTOP = $0033 ; Pointer: bottom of string storage +FRESPC = $0035 ; Utility string pointer +MEMSIZ = $0037 ; Pointer: highest address used by BASIC +CURLIN = $0039 ; Current BASIC line number +TXTPTR = $003B ; +FNDPNT = $003D ; +DATLIN = $003F ; Current DATA line number +DATPTR = $0041 ; Pointer: Current DATA item address +INPPTR = $0043 ; Vector: INPUT routine +VARNAM = $0045 ; Current BASIC variable name +VARPNT = $0047 ; Pointer: Current BASIC variable data +FORPNT = $0049 ; Pointer: Index variable for FOR/NEXT +OPPTR = $0048 ; +OPMASK = $004D ; +DEFPNT = $004E ; +DSCPNT = $0050 ; +HELPER = $0053 ; +JMPER = $0054 ; +SIZE = $0055 ; +OLDOV = $0056 ; +TEMPF1 = $0057 ; +HIGHDS = $0058 ; +HIGHTR = $005A ; +LOWDS = $005D ; +LoWTR = $005F ; +EXPSGN = $0060 ; +FACEXP = $0061 ; Floating-point accumulator #1: exponent +FACHO = $0062 ; Floating accum. #1: mantissa +FACMOH = $0063 ; +FACMO = $0064 ; +FACLo = $0065 ; +FACSGN = $0066 ; Floating accum. #1: sign +SGNFLG = $0067 ; Pointer: series evaluation constant +BITS = $0068 ; Floating accum. #1: overflow digit +ARGEXP = $0069 ; Floating-point accumulator #2: exponent +ARGHO = $006A ; Floating accum. #2: mantissa +ARGMOH = $006B ; +ARGMO = $006C ; +ARGLO = $006D ; +ARGSGN = $006E ; Floating accum. #2: sign +ARISGN = $006F ; Sign comparison result: accum. #1 vs #2 +FACOV = $0070 ; Floating accum. #1. low-order (rounding) +FBUFPT = $0071 ; Pointer: cassette buffer +AUTINC = $0073 ; Increment value for auto (0 = off) +MVDFLG = $0075 ; Flag if 10K hires allocated +KEYNUM = $0076 ; +KEYSIZ = $0077 ; +SYNTMP = $0078 ; Used as temp Eor indirect loads +DSDESC = $0079 ; Descriptor for DSS +TOS = $007C ; Top of run time stack +TMPTON = $007E ; Temps used by music (tone & volume) +VOICNO = $0080 ; +RUNMOD = $0081 ; +POINT = $0082 ; +GRAPHM = $0083 ; Current graphic mode +COLSEL = $0084 ; Current color selected +MC1 = $0085 ; Multicolor 1 +FG = $0086 ; Foreground color +SCXMAX = $0087 ; Maximum # of columns +SCYMAX = $0088 ; Maximum # of rows +LTFLAG = $0089 ; Paint-left flag +RTFLAG = $008A ; Paint-Right flag +STOPNH = $008B ; Stop paint if not BG (Not same Color) +GRAPNT = $008C ; +VTEMP1 = $008E ; +VTEMP2 = $008F ; +STATUS = $0090 ; Kernal I/O status word: ST +STREY = $0091 ; Flag: STOP key / RVS key +SPVERR = $0092 ; Temp +VERFCK = $0093 ; Flag: 0 = load, 1 = verify +C3PO = $0094 ; Plag: serial bus - output char buffered +BSOUR = $0095 ; Buffered character for serial bus +XSAV = $0096 ; Temp for basin +LDTND = $0097 ; # of open files / index to file table +DFLTN = $0098 ; Default input device (0) +DFLTO = $0099 ; Default output (CMD) device (3) +MSGFLG = $009A ; Flag: $80 = direct mode $00 = program +SAL = $009B ; Tape pass 1 error log +SAH = $009C ; Tape pass 2 error log +EAL = $009D ; +EAH = $009E ; +T1 = $009F ; Temp data area +T2 = $00A1 ; Temp data area +TIME = $00A3 ; Real-time jiffy clock (approx) 1/60 sec +R2D2 = $00A6 ; Serial bus usage (EOI on output) +TPBYTE = $00A7 ; Byte to be written/read on/off tape +BSOUR1 = $00A8 ; Temp used by serial routine +FPVERR = $00A9 ; +DCOUNT = $00AA ; +FNLEN = $00A8 ; Length of current file name +LA = $00AC ; Current logical fiie number +SA = $00AD ; Current seconda.y address +FA = $00AE ; Current device number +FNADR = $00AF ; Pointer: current file name +ERRSUM = $00B1 ; +STAL = $00B2 ; I/O start address +STAH = $00B3 ; +MEMUSS = $00B4 ; Load ram base +TAPEBS = $00B6 ; Base pointer to cassette base +TMP2 = $00B8 ; +WRBASE = $00BA ; Pointer to data for tape writes +IMPARM = $00BC ; Pointer to immediate string for primms +FETPTR = $00BE ; Pointer to byte to be fetched in bank fetc +SEDSAL = $00C0 ; Temp for scrolling +RVS = $00C2 ; RVS field flag on +INDX = $00C3 ; +LSXP = $00C4 ; X position at start +LSTP = $00C5 ; +SFDX = $00C6 ; Flag: shift mode for print +CRSW = $00C7 ; Flag: INPUT or GET from keyboard +PNT = $00C8 ; Pointer: current screen line address +PNTR = $00CA ; Cursor column on current line +QTSW = $00CB ; Flag: editor in quote mode, $00 = no +SEDT1 = $00CC ; Editor temp use +TBLX = $00CD ; Current cursor physical line number +DATAX = $00CE ; Temp data area +INSRT = $00CF ; Flag: insert mode, >0 = # INSTs +CIRSEG = $00E9 ; Screen line link table / editor temps +USER = $00EA ; Screen editor color IP +KEYTAB = $00EC ; Key scan table indirect +TMPKEY = $00EE ; +NDX = $00EF ; Index to keyboard queue +STPFLG = $00F0 ; Pause flag +TO = $00F1 ; Monitor ZP storage +CHRPTR = $00F3 ; +BUFEND = $00F4 ; +CHKSUM = $00F5 ; Temp for checksum calculation +LENGTH = $00F6 ; +PASS = $00F7 ; Which pass we are doing str +TYPE = $00F8 ; Type of block +USE4DY = $00F9 ; (B.7 = 1)=> for wr, (B.6 = 1)=> for rd +XSTOP = $00FA ; Save xreg for quick stopkey test +CURBNK = $00FB ; Current bank configuration +XoN = $00FC ; Char to send for a x-on (RS232) +XoFF = $00FD ; Char to send for a x-off (RS232) +SEDT2 = $00FE ; Editor temporary use +LOFBUF = $00FF ; + + +FBUFFR = $0100 ; +SAVEA = $0110 ; Temp Locations for +SAVEY = $0111 ; ... for Save and +SAVEX = $0112 ; ... Restore +COLKEY = $0113 ; Color/luminance table in RAM +SYSSTK = $0124 ; System stack +BUF = $0200 ; Basic/monitor input buffer +OLDLIN = $0259 ; Basic storage +OLDTXT = $025B ; Basic storage +XCNT = $025D ; DOS loop counter +PNBUFR = $025E ; Area for filename +DOSF1L = $026E ; DOS filename 1 length +DOSDS1 = $026F ; DOS disk drive 1 +DOSF1A = $0270 ; DOS filename 1 addr +DOSF2L = $0272 ; DOS filename 2 length +DOSDS2 = $0273 ; DOS disk drive 2 +DOSF2A = $0274 ; DOS filename 2 addr +DOSLA = $0276 ; DOS logical address +DOSEA = $0277 ; DOS phys addr +DOSSA = $0278 ; DOS secordary address +DOSDID = $0279 ; DOS disk identifier +DIDCHK = $0278 ; DOS DID flag +DOSSTR = $027C ; DOS output string buffer +DOSSPC = $027D ; Area used to build DOS string + +XPOS = $02AD ; Current x position +YPOS = $02AE ; Current y position +XDEST = $02B1 ; X coordinate destination +YDEST = $02B3 ; Y coordinate destination +XABS = $02B5 ; +YABS = $02B7 ; +XSGN = $02B9 ; +YSGN = $02BB ; +FCT1 = $02BD ; +FCT2 = $02BF ; +ERRVAL = $02C1 ; +LESSER = $02C3 ; +GREATR = $02C4 ; +ANGSGN = $02C5 ; Sign of angle +SINVAL = $02C6 ; Sine of value of angle +COSVAL = $02C8 ; Cosine of value of angle +ANGCNT = $02CA ; Temps for angle distance routines + +BNR = $02CD ; Pointer to begin no. +ENR = $02CE ; Pointer to end no. +DOLR = $02CF ; Dollar flag +FLAG = $02D0 ; Comma flag +SWE = $02D1 ; Counter +USGN = $02D2 ; Sign exponent +UEXP = $02D3 ; Pointer to exponent +VN = $02D4 ; # of digits before decimal point +CHSN = $02D5 ; Justify flag +VF = $02D6 ; # of pos before decimal point (field) +NF = $02D7 ; # of pos after decimal point (field) +POSP = $02D8 ; +/- flag (field) +FESP = $02D9 ; Exponent flag (field) +ETOF = $02DA ; Switch +CFORM = $02D8 ; Char counter (field) +SNO = $02DC ; Sign no. +BLFD = $02DD ; Blank/star flag +BEGFD = $02DE ; Pointer to beginning of field +LFOR = $02DF ; Length of format +ENDFD = $02E0 ; Pointer to end of field + +XCENTR = $02CC +YCENTR = $02CE +XDIST1 = $02D0 +YDIST1 = $02D2 +XDIST2 = $02D4 +YDIST2 = $02D6 + +COLCNT = $02DA ; Characters column counter +ROWCNT = $02DB ; Characters row counter +STRCNT = $02DC + + +XCORD1 = $02CC +YCORD1 = $02CE +BOXANG = $02D0 ; Rotation angle +XCOUNT = $02D2 +YCOUNT = $02D4 +BXLENG = $02D6 ; Length of a side +XCORD2 = $02D8 +YCORD2 = $02DA + +XCIRCL = $02CC ; Circle center, x coordinate +YCIRCL = $02CE ; Circle center, y coordinate +XRADUS = $02D0 ; X radius +YRADUS = $02D2 ; Y radius +ROTANG = $02D4 ; Rotation angle +ANGBEG = $02D8 ; Arc angle start +ANGEND = $02DA ; Arc angle end +XRCOS = $02DC ; X radius * cos (rotation angle) +YRSIN = $02DE ; Y radius * sin (rotation angle) +XRSIN = $02E0 ; X radius * sin (rotation angle) +YRCOS = $02E2 ; Y radius * cos (rotation angle) + + +KEYLEN = $02CD +KEYNXT = $02CE +STRS2 = $02CE ; String length +GETTYP = $02D0 ; Replace string mode +STRPTR = $02D1 ; String position counter +OLDBYT = $02D2 ; Old bit map byte +NEWBYT = $02D3 ; New string or bit map byte +XSIZE = $02D5 ; Shape column length +YSIZE = $02D7 ; Shape row length +XSAVE = $02D9 ; Temp for column length +STRADR = $02D8 ; Save shape string descriptor +BITIDX = $02DD ; Bit index into byte +SAYSIZ = $02DE ; Temporary work locations + +CHRPAG = $02E4 ; High byte addr of char ROM for char cmd +LITCNT = $02E5 ; Temp for gshape +SCALEM = $02E6 ; Scale mode flag +WIDTH = $02E7 ; Double width flag +FILFLG = $02E8 ; Box fill flag +BITMSK = $02E9 ; Temp for bit mask +NUMCNT = $02EA +TRCFLG = $02EB ; Flags trace mode + +T3 = $02EC +T4 = $02ED +VTEMP3 = $02EF ; Graphic temp storage +VTEMP4 = $02F0 +VTEMP5 = $02F1 + +ADRAY1 = $02E2 ; Ptr to routine: convert float to integer +ADRAY2 = $02F4 ; Ptr to routine: convert integer to float + +BNKVEC = $02FE ; Vector for function cartridge users +IERROR = $0300 ; Indirect Error (Output Error in .X) +IMAIN = $0302 ; Indirect Main (System Direct Loop) +ICRNCH = $0304 ; Indirect Crunch (Tokenization Routine) +IOPLOP = $0306 ; Indirect List (Char List) +IGONE = $0308 ; Indirect Gone (Character Dispatch) +IEVAL = $030A ; Indirect Eval (Symbol Evaluation) +IESCLK = $030C ; Escape token crunch +IESCPR = $030E ; +IESCEX = $0310 ; +ITIME = $0312 ; +CINV = $0314 ; IRQ Ram Vector +CBINV = $0316 ; BRK Instr RAM Vector +IOPEN = $0318 ; Indirects for Code +ICLOSE = $031A ; +ICHKIN = $031C ; +ICKOUT = $031E ; +ICLRCH = $0320 ; +IBASIN = $0322 ; +IBSOUT = $0324 ; +ISTOP = $0326 ; +IGETIN = $0328 ; +ICLALL = $032A ; +USRCMD = $032C ; +ILOAD = $032E ; +ISAVE = $0330 ; Savesp + +TAPBUF = $0333 ; Cassette tape buffer +WRLEN = $03F3 ; Length of data to be written to tape +RDCNT = $03F5 ; Length of data to be read from tape +INPQUE = $03F7 ; RS-232 input queue +ESTARL = $0437 +ESTAKH = $0455 + +CHRGET = $0473 +CHRGOT = $0479 +QNUM = $0485 + +INDSUB = $0494 ; Shared ROM fetch sub +ZERO = $04A2 ; Numeric constant for Basic + +INDTXT = $04A5 ; Txtptr +INDIN1 = $04B0 ; Index & Index1 +INDIN2 = $04BB ; Index2 +INDST1 = $04C6 ; Strng1 +INDLOW = $04D1 ; Lowtr +INDFMO = $04DC ; Facmo + +PUFILL = $04E7 ; Print using fill symbol [space] +PUCOMA = $04E8 ; Print using comma symbol [;] +PUDOT = $04E9 ; Print using D.P. symbol [.] +PUMONY = $04EA ; Print using monetary symbol [$] + +TMPDES = $04EB ; Temp for instr +ERRNUM = $04EF ; Last error number +ERRLIN = $04F0 ; Line # of last error +TRAPNO = $04F2 ; Line to go on error +TMPTRP = $04F4 ; Hold trap no. temporarily +ERRTXT = $04F5 +OLDSTR = $04F7 + +TMPTXT = $04F8 +TMPLIN = $04FA + +MTIMLO = $04FC ; Table of pending jiffies (2's comp) +MTIMHI = $04FE +USRPOK = $0500 +KERNDX = $0503 +DEJAVU = $0508 ; 'cold' or 'warm' start status + +LAT = $0509 ; Logical file numbers +FAT = $0513 ; Primary device numbers +SAT = $051D ; Secondary addresses + +KEYD = $0527 ; IRQ keyboard buffer +MEMSTR = $0531 ; Start of memory [1000] + +MSIZ = $0533 ; Top of memory [FD00] +TIMOUT = $0535 ; IEEE timeout flag + +FILEND = $0536 ; File end reached = 1, 0 otherwise +CTALLY = $0537 ; # of chars left in buffer (for R & W) +CBUFVA = $0538 ; # of total valid chars in buffer (R) +TPTR = $0539 ; Ptr to next char in buffer (for R & W) +FLTYPE = $053A ; Contains type of current cass file + +COLOR = $053B ; Active attribute byte +FLASH = $053C ; Character flash flag +HIBASE = $053E ; OC Base location of screen (top) [0C] +XMAX = $053F ; +RPTFLG = $0540 ; Key repeat flag +KOUUT = $0541 ; +DELAY = $0542 ; +SHFLAG = $0543 ; Shift flag byte +LSTSHF = $0544 ; Last shift pattern +KEYLOG = $0545 ; Indirect for keyboard table setup +MODE = $0547 ; shift, C= +AUTODN = $0548 ; Auto scroll down flag (0=on,0off) +LINTMP = $0549 +ROLFLG = $054A + +FORMAT = $054B ; Monitor non-zpage storage +MSAL = $054C +WRAP = $054F +TMPC = $0550 +DIFF = $0551 +PCH = $0552 +PCL = $0553 +FLGS = $0554 +ACC = $0555 +XR = $0556 +YR = $0557 +SP = $0558 +INYL = $0559 +INVH = $055A +CMPFLG = $055B ; Used by various monitor routines +BAD = $055C + +KYNDX = $055D ; Used for programmable keys +KEYIDX = $055E ; +KEYBUF = $055F ; Table of P.F. lengths +PKY9UF = $0567 ; P.F. Key storage area + +KDATA = $05E7 ; Temp for data write to kennedy +RDYCMD = $05E8 ; Select for kennedy read or write +KDYNUM = $05E9 ; Kennedy's dev # +RDYPRS = $05EA ; Rennedy present = $ff, else = $00 +KDYTYP = $05EB ; Temp for type of open for kennedy + + +SAVRAM = $05EC ; 1 page used by banking routines +PAT = $05EC ; Physical Address Table +LNGJMP = $05F0 ; Long jump address +FETARG = $05F2 ; Long jump accumulator +FETXRG = $05F3 ; Long jump x register +FETSRG = $05F4 ; Long jump status register + +AREAS = $05F5 ; RAM areas for banking + +ASPECH = $065E ; RAM area for speech + +STKTOP = $06EC ; BASIC run-time stack + +WROUT = $07B0 ; Byte to be written on tape +PARITY = $07B1 ; Temp for parity calc + +TT1 = $07B2 ; Temp for write-header +TT2 = $07B3 ; Temp for write-header +RDBITS = $07B5 ; Local index for READBYTE routine +ERRSP = $07B6 ; Pointer into the error stack +FPERRS = $07B7 ; Number of first pass errors + +DSAMP1 = $07B8 ; Time constant +DSAMP2 = $07BA ; Time constant +ZCELL = $07BC ; Time constant + +SRECOV = $07BE ; Stack marker for stopkey recover +DRECOV = $07BF ; Stack marker for dropkey recover +TRSAVE = $07C0 ; params passed to RDBLOK +RDETMP = $07C4 ; Temp stat save for RDBLOK +LDRSCN = $07C5 ; # consec shorts to find in leader +CDERRM = $07C6 ; # Errors fatal in RD countdown +VSAVE = $07C7 ; Temp for Verify command +T1PIPE = $07C8 ; Pipe temp for T1 +ENEXT = $07CC ; Read error propagate + + +UOUTQ = $07CD ; User chracter to send +UOUTFG = $07CE ; 0 = empty ; 1 = full +SOUT9 = $07CF ; System character to send +SOUNFG = $07D0 ; 0 = empty ; 1 = full +INOFPT = $07D1 ; Pntr to front of input queue +INQRPT = $07D2 ; Pntr to rear of input queue +INQCNT = $07D3 ; # of chars in input queue +ASTAT = $07D4 ; Temp status for ACIA +AINTMP = $07D5 ; Temp for input routine +ALSTOP = $07D6 ; FLG for local pause +ARSTOP = $07D7 ; FLG for remote pause +APRES = $07D8 ; FLG to indicate presence of ACIA + +RLUDES = $07D9 ; Indirect routine downloaded +SCBOT = $07E5 ; Screen bottom (0...24) +SCTOP = $07E6 ; Screen top +SCLF = $07E7 ; Screen left (0...39) +SCRT = $07E8 ; Screen right +SCRDIS = $07E9 ; Negative = scroll out +INSFLG = $07EA ; Insert mode: FF = on, 00 = off +LSTCHR = $07EB +LOGSCR = $07EC +TCOLOR = $07ED +BITABL = $07EE + +SAREG = $07F2 ; Registers for SYS command +SXREG = $07F3 +SYREG = $07F4 +SPREG = $07F5 + +LSTX = $07F6 ; Key scan index +STPDSB = $07F7 ; Flag to disable CTRL-S pause +RAMROM = $07F8 ; MSB for monitor fetches from ROM=0;RAM=1 + +COLSW = $07F9 ; MSB for color/lim table in RAM=0;ROM=1 +FFRMSK = $07FA ; ROM mask for split screen +VMBMSK = $07FB ; VM base mask for split screen +LSEM = $07FC ; Motor lock semaphore for cassette +PALCNT = $07FD ; PAL tod + + +TEDATR = $0800 ; TED attribute bytes +TEDSCN = $0C00 ; TED character pointers +BASBGN = $1000 ; Start of BASIC text area +BMLUM = $1800 ; Luminance for bit map screen +BMCOLR = $1C00 ; Color for bit map + +; KERNAL JUMP TABLE + +CINT = $ff81 ; Initialize screen editor +IOINIT = $ff84 ; Initialize I/O devices +RAMTAS = $ff87 ; Ram test +RESTOR = $ff8a ; Restore vectors to initial values +VECTOR = $ff8d ; Change vectors for user +SETMSG = $ff90 ; Control O.S. messages +SECND = $ff93 ; Send SA after LISTEN +TKSA = $ff96 ; Send SA after TALK +MEMTOP = $ff99 ; Set/Read top of memory +MEMBOT = $ff9c ; Set/Read bottom of memory +SCNKEY = $ff9f ; Scan keyboard +SETTMO = $ffa2 ; Set timeout in DMA disk +ACPTR = $ffa5 ; Handshake serial bus or DMA disk byte in +CIoUT = $ffa8 ; Handshake serial bus or DMA disk byte out +UNTLR = $ffab ; Send UNTALK out serial bus or DMA disk +UNLSN = $ffae ; Send UNLISTEN out serial bus or DMA disk +LISTN = $ffb1 ; Send LISTEN out serial bus or DMA disk +TALK = $ffb4 ; Send TALK out serial bus or DMA disk +READST = $ffb7 ; Return I/O STATUS byte +SETLFS = $ffba ; Set LA, FA, SA +SETNAM = $ffbd ; Set length and FN address +OPEN = $ffc0 ; Open logical file +CLOSE = $ffc3 ; Close logical file +CHKIN = $ffc6 ; Open channel in +CHOUT = $ffc9 ; open channel out +CLRCHN = $ffcc ; Close I/O channels +BASIN = $ffcf ; Input from channel +CHRIN = BASIN +BSOUT = $ffd2 ; output to channel +CHROUT = BSOUT +LOADSP = $ffd5 ; Load from file +SAYESP = $ffd8 ; Save to file +SETTIM = $ffdb ; Set internal clock +RDTIM = $ffde ; Read internal clock +STOP = $ffe1 ; Scan STOP key +GETIN = $ffe4 ; Get character from queue +CLALL = $ffe7 ; Close all files +UDTIM = $ffea ; Increment clock +SCRORG = $ffed ; Screen org. +PLOT = $fff0 ; Read/Set X,Y coord of cursor +IOBASE = $fff3 ; Return location of start of I/O + + .pron + +; vim: syntax=64tass diff --git a/run-tests.sh b/run-tests.sh new file mode 100755 index 0000000..0a5bf4a --- /dev/null +++ b/run-tests.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +X64="x64 -minimized +sound -warp -silent +saveres" +PRG="chipty5-64.prg" + +LBL=$(basename "$PRG" .prg).l + +MONSCRIPT="load \"${PRG}\" 0\n +load_labels \"${LBL}\"\n +bload \"/tmp/c8test.ch8\" 0 .C8ENTRY\n +break exec .oINV\n +goto .MainEntry\n +bsave \"/tmp/c8registers.bin\" 0 .reg:v .reg:st\n +bsave \"/tmp/c8display.bin\" 0 .c8screen .c8screenend\n +bsave \"/tmp/c8ram.bin\" 0 .C8RAM .c8ramend\n +quit" + +success () { + echo "$(tput setaf 2)Ok$(tput sgr0)" +} + +failure () { + echo "$(tput setaf 1)Failed $1$(tput sgr0)" + exit 1 +} + +if [ $# -gt 0 ] ; then + TESTS="$@" +else + TESTS=$(find tests -mindepth 1 -maxdepth 1 -type f \ + -name "*.ch8asm" -printf "%f\\n" | sed 's/\.ch8asm$//g') +fi + +make $PRG + +for testcase in $TESTS ; do + echo -n "Running test case $testcase ... " + cp tests/$testcase.ch8asm /tmp/c8test.ch8asm + ./ch8asm.py /tmp/c8test.ch8asm + $X64 -initbreak ready -moncommand <(echo -e $MONSCRIPT) >/tmp/c8test.vice.log 2>&1 + if [ -f tests/$testcase.display.pbm ] ; then + convert -size 64x32 -depth 1 gray:/tmp/c8display.bin -compress none -negate /tmp/c8display.pbm + cmp -s /tmp/c8display.pbm tests/$testcase.display.pbm || failure "(display)" + fi + if [ -f tests/$testcase.registers.regex ] ; then + grep -f tests/$testcase.registers.regex <(xxd -ps /tmp/c8registers.bin) >/dev/null || failure "(registers)" + fi + if [ -f tests/$testcase.ram.regex ] ; then + grep -f tests/$testcase.ram.regex <(xxd -g1 /tmp/c8ram.bin) >/dev/null || failure "(ram)" + fi + success +done diff --git a/samples/15puzzle.ch8 b/samples/15puzzle.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..3ef0bc8e6937b45b8ce559f520fe59ff20ab494b GIT binary patch literal 384 zcmZR0ki+1^kjKA>IYHq=D8mD#eM)6YeM)gkZbAZy3`ye2ERF&U?-srIDEA@NfkDXR zgXSgELdGK26y_Eo69yrrB=KT4AtfO1Q7Uumr6~an?_8J}-lZ_MJW*OE<c1>702KcZ z7LQBe0jlSLst1Yx0gIQRi1Pr&S-|3bi(Y&I+P~<<Ke-Q~2@GIfXrBYaI~xX}OG+|I zH<V-+{rC%1(F-)I=KooKhIh4$3H-fGZ|4c!c)L*O5yLx1CT12^Hg*n9E^Z!PK7IyX U21X{J0Fcka$IQ;nKT!4q09o#hE&u=k literal 0 HcmV?d00001 diff --git a/samples/delaytest.ch8 b/samples/delaytest.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..b9879385df290cf87577312067f425b98f24388b GIT binary patch literal 58 zcmYdcP?Gz~<;qmX=*m&{-;`B|>6_>`b|pD81|bn4CWZ%#tiBn4N=;_?pn2J~nDrx= K`~)N!-T?pvwG=%7 literal 0 HcmV?d00001 diff --git a/samples/ibmlogo.ch8 b/samples/ibmlogo.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..113338e67097e0a2ad227e5b79b3a5d1a586a660 GIT binary patch literal 132 zcmZR0ut+O`Cz0cVd;#Yo%M0?0JPJT;mPO$}l4DUCm@K^@FQoCG;Xi{76av{Gt_6cV z5Ly6P{~H({0AT|Vg6SU&e;Dk5a@Gu%3_lotFf*_-@H6aZ_|5Q{;W2|VOes`300ZwW A9{>OV literal 0 HcmV?d00001 diff --git a/samples/invaders.ch8 b/samples/invaders.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..f7db5f53b5006da92a38a2c0091e6da986ef6138 GIT binary patch literal 1283 zcmZWnVMtq76h1F~J|7Zjc4OEbmh`cwLu6gw(6#9rW=$iB41#SRE68BaFdx&rY8P2a z+a!%KrZ91cKL)z6vDudQXQO|{*dGybj_pqcJ8;NmevDcF#4v<ti8nhhvF&gl@1A?^ zckVskIrl!&a;3NHVz<;2daujheff%XLwVzz<hv>P`)>?>C|&Idsoj?~=!dX4zqU$0 z7XNX-DUnmx#ePsOkW+(ohHDt)yIMohRjgNlyer>La->^_k4_B25FcqU_-o$b<B*pl za^S$F@%b-FLXLPKR*@r`fU8Mdor`gD<P4Cnv^r$Ab#9<3lbV0@_>wg~sk~Jo-|9fN zA7AR^EUUx#h0$Z<--q|cUk!`xKz@-&)51lOthGDHZ<gOq$sbitB3tdPWLqA62b}dc zg&z8>s>E)!s(>6haFLNx{aGL*2QE1<dG9=NHpOj2<?}YDj599>yp)VU{@$9_*e`~U zub#Y)x1hZ4Y%exI{=qIAAT9Gh?7RC#`GYax#kjo+g;YL86xdj~ZHL1ABkjaG4+S~! znJfpix+1OJnez@5hF~fm;kUmgS0C68+{FQ<;=Dfu5&jxC%sHp-L(z>n!~}PXd%NB_ z1qE-iQkk7a)7-q3ta!c2jWHi`8xBvL0o;L38~_~09YX+gN{8qa#R>p}G7f;G&lg4j zAXfuA6-Yo=qArmDSXx@~8?BzB@sgvlRN{GnxSuT{j>dPS)+bL+p9a{U_zAIpG`;|m zA}uTcl=!WQiOlZN`1AUAT6Z9?jr=eEto}t<v;a`%4^ehFD*IzUPR`9eg{Pm+&3!Su z_jgOnZbwH4yxiDv_RMQPZ}#@SzrMZ+n=hRtO|SfpEo8IVa)zbTjHNIcE2pugGE42D z&r(H;N-bowxXs$>sDe@&490TP4;LTiQq@z1nHh|-G@5MOvT>GXcs8D1`gQph%d+WQ zhAlFijWLIUNLwl>nl5-8+3e>tGljI@<MAWGFv@K1V#<0U5Ck-uhCNz9T?#b5Vn>V5 zh&!r^OcX_oFdHf|JSzw+v%JiBo~0Q2Rtwmj%_ay!wO@uy^!?0_pIL*^2X<;Ip(GHh z8)l!bHtP@!Qeq0zCV`|v%#0F>QoXi)T8){(m=QGzHKMvYZARPvb2_SG0-B_usKqOK zHLszlq1>TbP)$-3bLghgru1RvXq&liLWr1ueN&x`HdT$*_&;;i<aRaK7qj%E)aNsh of@<;?B`YDjPQjpul5SPE)129?s>Jlg>|XP`L+$53d+ko)Us1r}6951J literal 0 HcmV?d00001 diff --git a/samples/lunarlander.ch8 b/samples/lunarlander.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..e7972b5bd75793eb598e83cf3d2326a459f5b5f1 GIT binary patch literal 1792 zcmZWq3rtg282)cd0r3H8ZSM^(^1Lmmfr^<S_^MTG12{FI%q(;1EzB7dD9=`?a8<xs z6@lR+CR-}>)&>k3<~9>VS>|S4wuQ3cWlkKM#<;p&>m!CR<nG*7aF4(F@A>b4zH@rc z|9$6Nsi;u>Ozv7pNlZZQab;4GCMmhgRX~9$mei73{4^kQ{fgefmr#La#7UP?X|r*r z{4<v?*hezv$rVrEFI-*}p12*jK<W?Km69jH=Tr0q4$X3lBG5>Zsr)O1lnF?b|CUk* z^EFeUd~7IRJh^+4F~6RZsSL)!QA|xReuV_sDY_B83oLU>MTMe!XOo5t!|t6WZH3_| zE|os8VJ(Aod@d;7%Z*LysOPO%l7B5o{ezeqWRVt37G>cRoryV#=M$@v{E3$nk4lFC zgqdW+z!gIA$=#EC!n!sI>m<{<45*z?rXhS4LV5xG4!@)2q5Yv9?FJcV=j<(9<Ne0_ z!Pi<o3uL#5e1I2(1*_$AfXGks3u}{=0%zd|C#Lyvx~q}GO!It7;K-}4-%w34U%Kl_ zMYJ!S0ZJ*n1>?okd=ueQF(efyw641d8RttVk6f;neJxb;1tBY14K_Y^QuZJ>R`#F{ zv+`@9o_GDsHkBbJ57T=k$IN4GTQJ3sV{K)yFG7g%=VNUGLiPrL0~vSZo1Qa{E0?Z# z&g-&u+11%a`FYu#r`N*;h62uuaLRSVb!uCFIhpX~`k$~bdX}zQvSh?C(lK@?(yRA| zdJW~t@f);{v>OhJ`ssuH(hu9)2Tpu+Vjz3t#*Nin%3F5s@v-BMN0xlcwzmz2>a7Og z94!t%=epn6=<o4&cgM#&jq#j^>+F5Jc}q@iRe>SDYKLLRh~ZtmUhfSTfGsV;V#hVe zgt8w9vJk9&Be9y{2Y?p3G#X>b%;wn^4L~NwqN6cnL81U6qG#<mvXqG_o7HBEQLC*J zfeEAtD3bWdO6>XK^2ilpd4^E$f91mDoBo%R$lpPnrpeQgYq7975EcO<3_iJr)WFZG z0qIq418%#X`53XiP<}>Gf;gIQh`@MYT+|#>v@e00Yl`tD;1y(hl7n>1l%W<losQ-` zJ)T}WAE2GI(;0vnH49okw})-kVTvrB2)P(}7;*{naOBAfsg6XhR7gvBMHWCQSVWAM z-EZaVv9<FR1as5!+={V>ERoC*dkCMJuzTzt&%}Rm8id0_IClnnXbq1~5sEU{DQW&{ z9j2h=qpvCq13a^u$c(X$j#^_f!ELdKtS?!+(xW))wy<`0g=N|r#x}X?sd>U#D-pdU z6sO7S|J)C7>vMW{^bcIU*mo&Uqu;Dszd`$Haq6;r*MCWmOSi|X^ra%@9bAL--0b$U z%~pPzn3-=MwkAq(w*;M0_b~eB`Az0#nl>M%+5PN(RhE@EW7T}k^xkRq0DEAleW-oJ zG-BF^sj_CqyNB0E@CA4#UQjBUCV;a>DaRF)xV8i)2&KniK0?<?fSW;|E5=Q?`vfFj zFgO?#WHLIpxGw=XuDjRs@KH`qPHtykx4To_Dr?O&$JA)d<MHT6v?InN$z6dc4TfLT zi16<<Vtf>L5>DgXfWdgOOBFD5r5Yy#hR*Md5HR3={0{);f^k8>;HHRfqR&_qM8pRX zu>r%gh!ueQVO*+I>1!htx32Y<fpIy_tOFt=4+w1@hFnBwiIo7TXG^Gu2uJsGCnZK) zyxMU}GLeyz?7D)q7*3`UD^c8nz8c}Ame3ZT74DGNoC=I0KE>_|wux<;xj%(^)bTc? zmfS^29jk!Ysq~;Vi4kk#xW-*cEfTbTt`<K7;HHd{fPuMy_Zh`#-(LJO%AlxAh2O4u zk<kD#1n~7YUea6Nyy;5&fCf4S%J_!LOt^`EuIgF`(Bb7D^M86<r>A&Ts=9UiQ7PZh OU}>Y{emAkJmi`U7_r^>B literal 0 HcmV?d00001 diff --git a/samples/opcodes.ch8 b/samples/opcodes.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..f540f69ecfc06e6c7b30881234469cc10847bff9 GIT binary patch literal 478 zcmYk&ze~eF6bJC8;uTt`rKMFO)T4t#DiW)7aF9c=aT1sA@kf%j0Y~YWsiDx-J-lv3 z1R;Mw{sLz$9o|@rh&s6H-K7zi<L>jmckgk<v&H>n@idt{U=U!$7$S`jO^N|hYBI{u zLvEBJ7rsFj@J-|)dXX2fAb|8VOudV>H0vnc)n3+BEX}S%<vE0-mk`p;I*@7T5>S^y zPBf8sb5KpBZAvM?b|SYwtvFSN-Nf$VlnRYlYR8@R?q-j=3S_x7MK{?=<EJb?5&zss zdI`%5b2R_as4x2oEef^!&X#{^Y)CJI@XDWG8IE*Sx+;C-jQs03-`VNvy#qdlxK&+N z`@Uto{hOyI9S1k9NNP@|#mvNB8`!Ok)B+sFZ;a<=>O%i)k6%A5AWWClvaIsC#&di4 cz5iuFT33MVtpI6c<S(m`=lA))7f(yGUqw*nbpQYW literal 0 HcmV?d00001 diff --git a/samples/pong.ch8 b/samples/pong.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..65d63106cc088da4fc0e2cfad10e01453e724620 GIT binary patch literal 246 zcmc~|%I3+j&*fS4>ejY9*YX&YuB0(%FeM~>5dFYzz#t@bT)dnk^Z%j`*9svj5*QyW ztp1n40wkFd<hz+}ZR;&Kz*YOtfuWWufgwS@m+8(mkm|OU_9+SWZA^*s?Lux$LKSZI zLQU@Sng87xG8wNG3Tb69B{Mb@G;9^>%J`Se1!P^dXB1kL$kZSTq<4YI6JYXCg2D$0 zr7L|VK$qDWGXh=r&zLcTNl2{nzvsWq|3W7!89kXY853AONR%<UIh6eq%31X3pYf;E akD4hWsSH;_OGH0uUI}G**8l+wAOHX*Vqww% literal 0 HcmV?d00001 diff --git a/samples/rndtest.ch8 b/samples/rndtest.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..a6225e5457a4db69208e77587f73afd102909cc9 GIT binary patch literal 34 lcmYdgV0du&|01Q&#-CDC7(QrT2`yp$2qr%P$<JIuOaLC74|xCp literal 0 HcmV?d00001 diff --git a/samples/tetris.ch8 b/samples/tetris.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..9f5e0874dbd03b5e99d32a1d81fe3cb343904cb4 GIT binary patch literal 494 zcmYk2yGsK>5XNWCX+%VlyR+~?lv`40<uh6+w{Tk7*w~4zO3oL``7DgeA!4PXAeLfM zsDD7PUeG^awHKn`t2s1i3JcFkNYI6EzL{@+#jvR~eKxKfBExM_wPMkiVP21lwu4%8 z;|w@z<8^>X#skLaSFO}dqV`E0DV;L4@g-?2y(W#Fx1@3Mc&ZNDkgLrFV^Cm-+M2rg zjM!iiTd~UQN-JPj=OW-q-SKIcNeUgIT_rCjxXUNY#8M`~7%h>@zU5Ei75S|TQ{~eY zGs<{VJTwsmk7WRuU;r5gjH4KbX3PZ3XD-eHy%{*pF6K<QAo!oV0y!?A<O1>kV))=4 z`JzkR?q2g_p!I^6O7DgGA{(S6IyO{AmyQH@i$ojd4RavFCM58G9nu!nCcxtj#eU@= zw4d4X3(SKF+M#^Vj^%BF6v*8n(9SpgEx(^=+f<l@iglEGHXn5Fn6mmaSQb~nyMXM- krSjdGjlZ|dcPzmD(`NZcOTK2Y;x?X2gEtGj4!j=v3%#qWWdHyG literal 0 HcmV?d00001 diff --git a/samples/worm.ch8 b/samples/worm.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..03bc7b8f7e3944fa02de9c45f1f8e8d6382bffd0 GIT binary patch literal 677 zcmWfN3C}OeRVdRl(NRdMv{DFi(ot~E$SlycP$)|+D$dN$0}J~m7L{aX<tc=x=9OgT zr7P$w1f`Z`mL=vW1ecViWabw$1UXq6F)%R5GcX9(Ffg$3F*2|)JXqxWFLm+K521hL z3K<O<gi;pw-`c#m?~39T!xAPFE1{CbbCMY@D_&77Vl<K$YFgy+A$1Yc2jfLdUyYTO zluH)RzMfddWTq%ICz<WD=;Eb6<UXXfFf=RxvqG1E`Hc(>8^Em4#gj}Jt_Uw~`ziM^ zb@9|&o4Q!KML_o1GYH!p;CEn9E~sFf@gRc%WLDb$M7D<u(-;z&fFx5Q3y@?<<N%Uv zX8$`AKC>G$2z?V;rmO^VNisu<%_62xsUI}2m=?2r1e2eDB*Q!929Wt+8-h}pzDSfZ zD$5AHN#Xh;acgrIYqu!K6<|MkG=w$;_%nP670#<;WO%oD`WgGP@^`NIGl1B4t_YX0 gFfjc2!@$6D-~kXUc);Lb5K&?9p#cVf;X0xL0HtZG$N&HU literal 0 HcmV?d00001 diff --git a/sid.asm b/sid.asm new file mode 100644 index 0000000..edf5bd1 --- /dev/null +++ b/sid.asm @@ -0,0 +1,52 @@ +; +; SID registers +; + + .virtual +_sid .struct +_sid_voice .struct +freq .word ? +duty .word ? +ctrl .byte ? +ad .byte ? +sr .byte ? + .endstruct +voice1 .dstruct _sid_voice +voice2 .dstruct _sid_voice +voice3 .dstruct _sid_voice +ffreq .word ? +fres .byte ? +volume .byte ? +potx .byte ? +poty .byte ? +osc3 .byte ? +env3 .byte ? + .endstruct + .endvirtual + +PAL_CLOCK = 985248 +NTSC_CLOCK = 1022727 + +sid_freq .sfunction freq, clock=PAL_CLOCK, int(freq*16777216/clock) +sid_duty .sfunction duty, int(duty*(1<<12)) + +SID_CTRL_NOISE = %1000_0000 +SID_CTRL_PULSE = %0100_0000 +SID_CTRL_SAWTOOTH = %0010_0000 +SID_CTRL_TRIANGLE = %0001_0000 +SID_CTRL_TEST = %0000_1000 +SID_CTRL_RING = %0000_0100 +SID_CTRL_SYNC = %0000_0010 +SID_CTRL_GATE = %0000_0001 + +SID_RES_EXT = %0000_1000 +SID_RES_V3 = %0000_0100 +SID_RES_V2 = %0000_0010 +SID_RES_V1 = %0000_0001 + +SID_FILTER_MUTE3 = %1000_0000 +SID_FILTER_HIGHPASS = %0100_0000 +SID_FILTER_BANDPASS = %0010_0000 +SID_FILTER_LOWPASS = %0001_0000 + +; vim: syntax=64tass diff --git a/ted.asm b/ted.asm new file mode 100644 index 0000000..0031414 --- /dev/null +++ b/ted.asm @@ -0,0 +1,43 @@ +; +; TED registers +; + + .virtual +_ted .struct +timer1 .word ? +timer2 .word ? +timer3 .word ? +vscroll .byte ? +hscroll .byte ? +kbdlatch .byte ? +irr .byte ? +imr .byte ? +irq_rasterline .byte ? +cursor_hi .byte ? +cursor_lo .byte ? +freq1 .byte ? +freq2 .word ? +snd_ctrl .byte ? +misc .byte ? +char_addr .byte ? +video_addr .byte ? +bgcolor .byte ? +color1 .byte ? +color2 .byte ? +color3 .byte ? +bordercolor .byte ? +bmap_reload_hi .byte ? +bmap_reload_lo .byte ? +rasterline_hi .byte ? +rasterline_lo .byte ? +rastercolumn .byte ? +cursor_blink .byte ? +unused .fill 30 +enable_rom .byte ? +enable_ram .byte ? + .endstruct + .endvirtual + +ted_freq .sfunction freq, int(1024-111860.781/freq) + +; vim: syntax=64tass diff --git a/template.asm b/template.asm new file mode 100644 index 0000000..9a75883 --- /dev/null +++ b/template.asm @@ -0,0 +1,13 @@ +; +; Description +; + + .section code + +Hello .proc + rts + .endproc + + .endsection code + +; vim: syntax=64tass diff --git a/tests/add.ch8asm b/tests/add.ch8asm new file mode 100644 index 0000000..5ca3216 --- /dev/null +++ b/tests/add.ch8asm @@ -0,0 +1,36 @@ +; +; Exercise ADD opcodes +; + + ; preload some values + LD Va, 12 + LD Vb, 34 + LD Vc, 12 + LD Vd, 89 + LD Ve, ff + + LD V0, 01 + LD Vf, aa + ADD V0, 11 ; ADD Vx, nn - no carry + LD V1, Vf + + LD V2, b6 + LD Vf, aa + ADD V2, 7e ; ADD Vx, nn - carry + LD V3, Vf + + LD V4, 22 + LD Vf, aa + ADD V4, Vb ; ADD Vx, Vy - no carry + LD V5, Vf + + LD V6, ef + LD Vf, aa + ADD V6, Vd ; ADD Vx, Vy - carry + LD V7, Vf + + LD I, 0f01 + ADD I, Ve + + EXIT + diff --git a/tests/add.registers.regex b/tests/add.registers.regex new file mode 100644 index 0000000..d6abed1 --- /dev/null +++ b/tests/add.registers.regex @@ -0,0 +1 @@ +12aa34aa56007801....12341289ff010010...... diff --git a/tests/bcd.ch8asm b/tests/bcd.ch8asm new file mode 100644 index 0000000..4dc40c7 --- /dev/null +++ b/tests/bcd.ch8asm @@ -0,0 +1,12 @@ +; +; BCD conversion test +; + + LD V0, 7b ; 123 (dec) + LD V4, 0 + LD I, 400 + LD B, V0 + LD V2, [I] + + EXIT + diff --git a/tests/bcd.ram.regex b/tests/bcd.ram.regex new file mode 100644 index 0000000..0d8a621 --- /dev/null +++ b/tests/bcd.ram.regex @@ -0,0 +1 @@ +00000400: 01 02 03 diff --git a/tests/bcd.registers.regex b/tests/bcd.registers.regex new file mode 100644 index 0000000..c0cf692 --- /dev/null +++ b/tests/bcd.registers.regex @@ -0,0 +1 @@ +010203..........................0004...... diff --git a/tests/bit.ch8asm b/tests/bit.ch8asm new file mode 100644 index 0000000..4af8bef --- /dev/null +++ b/tests/bit.ch8asm @@ -0,0 +1,37 @@ +; +; Exercise bitwise opcodes +; + + ; preload some values + LD Va, 12 + LD Vb, 34 + LD Vc, 55 + LD Vd, aa + LD Ve, f0 + + LD V0, 08 + OR V0, Va + + LD V1, 51 + AND V1, Ve + + LD V2, 65 + XOR V2, Vd + + LD V3, 30 + SHL V3, Vc + LD V4, Vf + + LD V5, 50 + SHR V5, Vd + LD V6, Vf + + LD V7, 70 + SHL V7, Ve + LD V8, Vf + + LD V9, 90 + SHR V9, Vd + + EXIT + diff --git a/tests/bit.registers.regex b/tests/bit.registers.regex new file mode 100644 index 0000000..6ef6818 --- /dev/null +++ b/tests/bit.registers.regex @@ -0,0 +1 @@ +1a50cfaa005500e0012a1234aa2ae001.......... diff --git a/tests/call.ch8asm b/tests/call.ch8asm new file mode 100644 index 0000000..0c7fecf --- /dev/null +++ b/tests/call.ch8asm @@ -0,0 +1,21 @@ +; +; Exercise JP/CALL/RET +; + + LD V0, 9 + CALL sub1 + LD V2, 9 + CALL sub2 + LD V4, 9 + JP skip + LD V4, 0 +skip LD V5, 9 + + EXIT + +sub1 LD V1, 1 + RET + +sub2 LD V3, 2 + RET + diff --git a/tests/call.registers.regex b/tests/call.registers.regex new file mode 100644 index 0000000..ed9f4c3 --- /dev/null +++ b/tests/call.registers.regex @@ -0,0 +1 @@ +090109020909.............................. diff --git a/tests/hexspr.ch8asm b/tests/hexspr.ch8asm new file mode 100644 index 0000000..a0aac97 --- /dev/null +++ b/tests/hexspr.ch8asm @@ -0,0 +1,21 @@ +; +; Show built-in hex font +; + +SPRH = 5 ; Built-in fonts are 4x5 + + CLS + LD V0, 00 + LD V1, V0 + LD V2, V0 +next LD F, V0 + DRW V1, V2, SPRH + ADD V0, 01 + ADD V1, 08 + SE V1, 20 + JP next + LD V1, 00 + ADD V2, 08 + SE V2, 20 + JP next + EXIT diff --git a/tests/hexspr.display.pbm b/tests/hexspr.display.pbm new file mode 100644 index 0000000..5ed62a9 --- /dev/null +++ b/tests/hexspr.display.pbm @@ -0,0 +1,34 @@ +P1 +64 32 +1 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 1 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/tests/ld.ch8asm b/tests/ld.ch8asm new file mode 100644 index 0000000..bc6297d --- /dev/null +++ b/tests/ld.ch8asm @@ -0,0 +1,17 @@ +; +; Exercise LD opcodes +; + + LD V0, 55 + LD V1, V0 + LD V2, aa + LD V3, V2 + LD I, 400 + LD [I], V3 + LD I, 404 + LD [I], V3 + LD I, 403 + LD V1, [I] + + EXIT + diff --git a/tests/ld.ram.regex b/tests/ld.ram.regex new file mode 100644 index 0000000..1d506d5 --- /dev/null +++ b/tests/ld.ram.regex @@ -0,0 +1 @@ +00000400: 55 55 aa aa 55 55 aa aa diff --git a/tests/ld.registers.regex b/tests/ld.registers.regex new file mode 100644 index 0000000..7a6a922 --- /dev/null +++ b/tests/ld.registers.regex @@ -0,0 +1 @@ +aa55aaaa........................0304...... diff --git a/tests/registers.header.txt b/tests/registers.header.txt new file mode 100644 index 0000000..7d9c575 --- /dev/null +++ b/tests/registers.header.txt @@ -0,0 +1 @@ +V0V1V2V3V4V5V6V7V8V9VaVbVcVdVeVf< I>spdtst diff --git a/tests/skip.ch8asm b/tests/skip.ch8asm new file mode 100644 index 0000000..4365d4b --- /dev/null +++ b/tests/skip.ch8asm @@ -0,0 +1,37 @@ +; +; Exercise LD opcodes +; + + LD V0, 01 + SE V0, 01 ; SE Vx, nn - skip + LD V0, 00 + LD V1, 00 + SE V1, 01 ; SE Vx, nn - no skip + LD V1, 01 + LD V2, 01 + SNE V2, 00 ; SNE Vx, nn - skip + LD V2, 00 + LD V3, 00 + SNE V3, 00 ; SNE Vx, nn - no skip + LD V3, 01 + + ; prepare for register based skips + LD Va, 12 + LD Vb, 34 + LD Vc, 12 + + LD V4, 01 + SE Va, Vc ; SE Vx, Vy - skip + LD V4, 00 + LD V5, 00 + SE Va, Vb ; SE Vx, Vy - no skip + LD V5, 01 + LD V6, 01 + SNE Va, Vb ; SNE Vx, Vy - skip + LD V6, 00 + LD V7, 00 + SNE Va, Vc ; SNE Vx, Vy - no skip + LD V7, 01 + + EXIT + diff --git a/tests/skip.registers.regex b/tests/skip.registers.regex new file mode 100644 index 0000000..6f2fdfb --- /dev/null +++ b/tests/skip.registers.regex @@ -0,0 +1 @@ +0101010101010101.......................... diff --git a/tests/sprites.ch8asm b/tests/sprites.ch8asm new file mode 100644 index 0000000..0bcfaeb --- /dev/null +++ b/tests/sprites.ch8asm @@ -0,0 +1,86 @@ +; +; Exercise sprite drawing and test collision behaviour +; + +SPRH = 8 + + CLS + + LD V0, 00 + LD V1, 00 + LD I, .block + DRW V0, V1, SPRH + LD V2, Vf + + LD V0, 3c + LD V1, 00 + LD I, .square + DRW V0, V1, SPRH + LD V3, Vf + + LD V0, 0a + LD V1, 1c + DRW V0, V1, SPRH + LD V4, Vf + + LD V0, 3c + LD V1, 1c + DRW V0, V1, SPRH + LD V5, Vf + + LD V0, 14 + LD V1, 2a + LD I, .checker + DRW V0, V1, SPRH + LD V6, Vf + + LD V0, 1e + LD V1, 0a + LD I, .block + DRW V0, V1, SPRH + LD V7, Vf + + LD V0, 28 + LD V1, 0a + LD I, .corners + DRW V0, V1, SPRH + LD V8, Vf + + LD V0, 1e + LD V1, 0a + LD I, .center + DRW V0, V1, SPRH + LD V9, Vf + + LD V0, 28 + LD V1, 0a + DRW V0, V1, SPRH + LD Va, Vf + + EXIT + +.block DATA ffff + DATA ffff + DATA ffff + DATA ffff + +.square DATA ff81 + DATA 8181 + DATA 8181 + DATA 81ff + +.corners DATA 8100 + DATA 0000 + DATA 0000 + DATA 0081 + +.center DATA 0000 + DATA 0018 + DATA 1800 + DATA 0000 + +.checker DATA aa55 + DATA aa55 + DATA aa55 + DATA aa55 + diff --git a/tests/sprites.display.pbm b/tests/sprites.display.pbm new file mode 100644 index 0000000..d258432 --- /dev/null +++ b/tests/sprites.display.pbm @@ -0,0 +1,34 @@ +P1 +64 32 +1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 +1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 +1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 +1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 +1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 +1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 +1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 +1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 0 0 1 1 1 1 1 1 1 1 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 0 1 1 1 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 0 0 1 1 1 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 0 1 1 1 1 1 1 1 1 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 +0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 diff --git a/tests/sprites.registers.regex b/tests/sprites.registers.regex new file mode 100644 index 0000000..e34be76 --- /dev/null +++ b/tests/sprites.registers.regex @@ -0,0 +1 @@ +....000000000000000100........00.......... diff --git a/tests/sub.ch8asm b/tests/sub.ch8asm new file mode 100644 index 0000000..7470fc8 --- /dev/null +++ b/tests/sub.ch8asm @@ -0,0 +1,31 @@ +; +; Exercise SUB/SUBN opcodes +; + + ; preload some values + LD Va, 12 + LD Vb, 34 + LD Vc, 56 + LD Vd, 89 + LD Ve, ff + + LD V0, 24 + SUB V0, Va ; SUB Vx, Vy - no borrow + LD V1, Vf + + LD V2, 45 + SUB V2, Vd ; SUB Vx, nn - borrow + LD V3, Vf + + LD V4, 22 + SUBN V4, Vc ; SUBN Vx, Vy - no borrow + LD V5, Vf + + LD V6, 56 + SUBN V6, Vb ; SUBN Vx, Vy - borrow + LD V7, Vf + + ; TODO: Check corner case where one of the operands is Vf + + EXIT + diff --git a/tests/sub.registers.regex b/tests/sub.registers.regex new file mode 100644 index 0000000..e355cc1 --- /dev/null +++ b/tests/sub.registers.regex @@ -0,0 +1 @@ +1201bc003401de00....12345689ff00.......... diff --git a/via.asm b/via.asm new file mode 100644 index 0000000..a013eb4 --- /dev/null +++ b/via.asm @@ -0,0 +1,32 @@ +; +; 6522 (VIA) registers +; + + .virtual +_via .struct +iorb .byte ? +iora .byte ? +ddrb .byte ? +ddra .byte ? +t1c .word ? +t1l .word ? +t2c .word ? +sr .byte ? +acr .byte ? +pcr .byte ? +ifr .byte ? +ier .byte ? +ioran .byte ? + .endstruct + .endvirtual + +VIA_SR_OFF = 0 << 2 +VIA_SR_IN_T2 = 1 << 2 +VIA_SR_IN_CLOCK = 2 << 2 +VIA_SR_IN_EXT = 3 << 2 +VIA_SR_OUT_T2_FR = 4 << 2 +VIA_SR_OUT_T2_CB1 = 5 << 2 +VIA_SR_OUT_CLOCK = 6 << 2 +VIA_SR_OUT_EXT = 7 << 2 + +; vim: syntax=64tass diff --git a/vic2.asm b/vic2.asm new file mode 100644 index 0000000..fe3cb50 --- /dev/null +++ b/vic2.asm @@ -0,0 +1,76 @@ +; +; VIC-II registers +; + + .virtual +_vic2 .struct +m0x .byte ? +m0y .byte ? +m1x .byte ? +m1y .byte ? +m2x .byte ? +m2y .byte ? +m3x .byte ? +m3y .byte ? +m4x .byte ? +m4y .byte ? +m5x .byte ? +m5y .byte ? +m6x .byte ? +m6y .byte ? +m7x .byte ? +m7y .byte ? +mxx8 .byte ? +cr1 .byte ? +raster .byte ? +lpx .byte ? +lpy .byte ? +mxe .byte ? +cr2 .byte ? +mxye .byte ? +ptrs .byte ? +ir .byte ? +ie .byte ? +mxdp .byte ? +mxmc .byte ? +mxxe .byte ? +mxm .byte ? +mxd .byte ? +ec .byte ? +b0c .byte ? +b1c .byte ? +b2c .byte ? +b3c .byte ? +mm0 .byte ? +mm1 .byte ? +m0c .byte ? +m1c .byte ? +m2c .byte ? +m3c .byte ? +m4c .byte ? +m5c .byte ? +m6c .byte ? +m7c .byte ? + .align 64 + .endstruct + .endvirtual + +VIC2_BLACK = 0 +VIC2_WHITE = 1 +VIC2_RED = 2 +VIC2_CYAN = 3 +VIC2_VIOLET = 4 +VIC2_PURPLE = 4 +VIC2_GREEN = 5 +VIC2_BLUE = 6 +VIC2_YELLOW = 7 +VIC2_ORANGE = 8 +VIC2_BROWN = 9 +VIC2_LIGHTRED = 10 +VIC2_DARKGREY = 11 +VIC2_GREY = 12 +VIC2_LIGHTGREEN = 13 +VIC2_LIGHTBLUE = 14 +VIC2_LIGHTGREY = 15 + +; vim: syntax=64tass