First commit. C64, C16/+4 and PET 4016/4032 working.

This commit is contained in:
Maurizio Porrato 2021-07-19 07:55:07 +01:00
commit 178662a911
Signed by: guru
GPG Key ID: C622977DF024AC24
57 changed files with 4456 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
*[%~]
*.py[co]
*.prg
*.lst
*.ll
*.d64

26
Makefile Normal file
View File

@ -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")

483
c64.asm Normal file
View File

@ -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

103
c8loader-cbmdos.asm Normal file
View File

@ -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
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

293
ch8asm.py Executable file
View File

@ -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))

143
ch8dis.py Executable file
View File

@ -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)

816
chip-8.asm Normal file
View File

@ -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 #<C8START
sta reg.pc
.endif
.if (C8START >> 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
sta pc
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
.endif
.if (C8RAM & $00ff) != 0
adc #<C8RAM
.endif
sta zptr1
lda reg.i+1
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

230
chipty5-64.asm Normal file
View File

@ -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
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
lda #>DUTY
sta io.sid.voice1.duty+1
lda #<FREQ
sta io.sid.voice1.freq
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
ldy #>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

237
chipty5-pet40.asm Normal file
View File

@ -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
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
ldy #>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

230
chipty5-plus4.asm Normal file
View File

@ -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
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
sta io.ted.freq1
; 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
ldy #>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

15
crtc.asm Normal file
View File

@ -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

16
diags/grid.ch8asm Normal file
View File

@ -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

9
diags/keypad.ch8asm Normal file
View File

@ -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

4
diags/sound.ch8asm Normal file
View File

@ -0,0 +1,4 @@
LD V0, 78
LD ST, V0
.loop JP .loop

349
display-pet40.asm Normal file
View File

@ -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
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 #<title
jsr mySTROUT
rts
.endproc
.endsection code
.section zp
cursorpos .word ?
.endsection zp
.section data
.enc "screen"
title .null " chipty5 chip-8 emulator for the 6502 "
.enc "none"
.endsection data
; vim: syntax=64tass

11
layout.asm Normal file
View File

@ -0,0 +1,11 @@
* = ZP_START
.dsection zp
* = BASIC_START
.dsection stub
.dsection code
.dsection data
.dsection bss
; vim: syntax=64tass

60
macros.asm Normal file
View File

@ -0,0 +1,60 @@
;
; Macros for common tasks
;
BasicStub .macro entrypoint, lineno=10, align=16
.section stub
.word (+), \lineno
.null BTOK_SYS, format("%d", \entrypoint)
+ .word 0
.if \align > 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

195
pet.asm Normal file
View File

@ -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

585
plus4.asm Normal file
View File

@ -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

52
run-tests.sh Executable file
View File

@ -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

BIN
samples/15puzzle.ch8 Normal file

Binary file not shown.

BIN
samples/delaytest.ch8 Normal file

Binary file not shown.

BIN
samples/ibmlogo.ch8 Normal file

Binary file not shown.

BIN
samples/invaders.ch8 Normal file

Binary file not shown.

BIN
samples/lunarlander.ch8 Normal file

Binary file not shown.

BIN
samples/opcodes.ch8 Normal file

Binary file not shown.

BIN
samples/pong.ch8 Normal file

Binary file not shown.

BIN
samples/rndtest.ch8 Normal file

Binary file not shown.

BIN
samples/tetris.ch8 Normal file

Binary file not shown.

BIN
samples/worm.ch8 Normal file

Binary file not shown.

52
sid.asm Normal file
View File

@ -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

43
ted.asm Normal file
View File

@ -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

13
template.asm Normal file
View File

@ -0,0 +1,13 @@
;
; Description
;
.section code
Hello .proc
rts
.endproc
.endsection code
; vim: syntax=64tass

36
tests/add.ch8asm Normal file
View File

@ -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

View File

@ -0,0 +1 @@
12aa34aa56007801....12341289ff010010......

12
tests/bcd.ch8asm Normal file
View File

@ -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

1
tests/bcd.ram.regex Normal file
View File

@ -0,0 +1 @@
00000400: 01 02 03

View File

@ -0,0 +1 @@
010203..........................0004......

37
tests/bit.ch8asm Normal file
View File

@ -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

View File

@ -0,0 +1 @@
1a50cfaa005500e0012a1234aa2ae001..........

21
tests/call.ch8asm Normal file
View File

@ -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

View File

@ -0,0 +1 @@
090109020909..............................

21
tests/hexspr.ch8asm Normal file
View File

@ -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

34
tests/hexspr.display.pbm Normal file
View File

@ -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

17
tests/ld.ch8asm Normal file
View File

@ -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

1
tests/ld.ram.regex Normal file
View File

@ -0,0 +1 @@
00000400: 55 55 aa aa 55 55 aa aa

1
tests/ld.registers.regex Normal file
View File

@ -0,0 +1 @@
aa55aaaa........................0304......

View File

@ -0,0 +1 @@
V0V1V2V3V4V5V6V7V8V9VaVbVcVdVeVf< I>spdtst

37
tests/skip.ch8asm Normal file
View File

@ -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

View File

@ -0,0 +1 @@
0101010101010101..........................

86
tests/sprites.ch8asm Normal file
View File

@ -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

34
tests/sprites.display.pbm Normal file
View File

@ -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

View File

@ -0,0 +1 @@
....000000000000000100........00..........

31
tests/sub.ch8asm Normal file
View File

@ -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

View File

@ -0,0 +1 @@
1201bc003401de00....12345689ff00..........

32
via.asm Normal file
View File

@ -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

76
vic2.asm Normal file
View File

@ -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