Skip to content

Instantly share code, notes, and snippets.

@MagerValp
Created March 21, 2016 09:46
Show Gist options
  • Select an option

  • Save MagerValp/a51c5985eab3f25ddbe5 to your computer and use it in GitHub Desktop.

Select an option

Save MagerValp/a51c5985eab3f25ddbe5 to your computer and use it in GitHub Desktop.
My first C64 emulator, in AmigaE from 1996
-> emulate parts of a c64
OPT PREPROCESS
/* #define DEBUG */
MODULE 'tools/file', 'intuition/screens', 'graphics/gfx', 'dos/dos'
MODULE 'intuition/intuition'
-> the different memory parts
DEF mem=NIL:PTR TO CHAR,kernelrom=NIL:PTR TO CHAR,
basicrom=NIL:PTR TO CHAR,charrom=NIL:PTR TO CHAR,
io=NIL:PTR TO CHAR,size=NIL:PTR TO CHAR,
time=NIL:PTR TO CHAR,ddr,ioport,opcodes=NIL,
opcodelist[256]:LIST,cyclecount=0,verbose,
linelist[25]:ARRAY OF CHAR,skipmemtest=1
-> processor registers
DEF a=0,x=0,y=0,sp=0,pc=0,status=$20
PROC main() HANDLE
DEF l,state,i,s:PTR TO screen,w:PTR TO window,pcstr[39]:STRING,fh,
args:PTR TO LONG,rdargs,msg:PTR TO intuimessage
/*
FOR x:=0 TO 255
IF (x AND 7)=0 THEN PrintF('$\z\h[2] ',x)
status:=$35
PrintF(' \z\h[2]',ror(x))
IF (x AND 7)=7 THEN PrintF('\n')
ENDFOR
Raise("brk")
*/
-> parse command line args
args:=[0]
IF (rdargs:=ReadArgs('VERBOSE/S',args,NIL))=NIL THEN Raise("args")
IF args[0] THEN verbose:=1 ELSE verbose:=0
-> allocate ram and load roms
mem:=NewR(65536)
io:=NewR(4096)
kernelrom,l:=readfile('kernel.rom') ;-> IF l<>8192 THEN Raise("kern")
basicrom ,l:=readfile('basic.rom') ;-> IF l<>8192 THEN Raise("basi")
charrom ,l:=readfile('char.rom') ;-> IF l<>4096 THEN Raise("char")
size ,l:=readfile('6510size.tab') ;-> IF l<>256 THEN Raise("size")
time ,l:=readfile('6510time.tab') ;-> IF l<>256 THEN Raise("time")
opcodes ,l:=readfile('OpCodeList.asc')
opcodelist:=stringsinfile(opcodes,l,256)
PrintF('emulation buffers ok...\n')
-> Open and init screen
IF (s:=OpenScreenTagList(0,
[SA_WIDTH,336,
SA_HEIGHT,224+11,
SA_DEPTH,1]))=NIL THEN Raise("CHIP")
SetRGB4(s.viewport,0,1,2,10)
SetRGB4(s.viewport,1,7,7,15)
SetAPen(s.rastport,1)
SetBPen(s.rastport,0)
IF (w:=OpenWindowTagList(0,
[WA_WIDTH, 336,
WA_HEIGHT, 224+11,
WA_TITLE, '6510emu',
WA_CUSTOMSCREEN, s,
WA_IDCMP, IDCMP_VANILLAKEY,
WA_BACKDROP, TRUE,
WA_BORDERLESS, TRUE,
WA_ACTIVATE, TRUE,
0,0]))=NIL THEN Raise("CHIP")
clearscreen(s)
renderscreen(s,1024)
PrintF('screen ok...\n')
-> start the emulation
reset()
IF verbose=1 THEN PrintF('*** starting trace ***\n')
REPEAT
FOR i:=1 TO 100
state:=emulate()
/*
StringF(pcstr,'\z\h[4] \z\h[2] \z\h[2] \z\h[2] \z\h[2] \z\h[2] '+
' ',
pc,a,x,y,status,sp)
IF verbose=0 THEN StrAdd(pcstr,'off') ELSE StrAdd(pcstr,' on')
Move(s.rastport,0,233)
Text(s.rastport,pcstr,EstrLen(pcstr))
*/
IF (msg:=GetMsg(w.userport))<>NIL
IF mem[198]<mem[649]
mem[631+mem[198]]:=msg.code
mem[198]:=mem[198]+1
ENDIF
ReplyMsg(msg)
ENDIF
IF (Mouse()<>0) AND (s.mousey>207)
verbose:=1-verbose
IF verbose=0 THEN PrintF('*** stopping trace ***\n') ELSE PrintF('*** starting trace ***\n')
WHILE Mouse()<>0 ; ENDWHILE
ENDIF
ENDFOR
IF CtrlC() THEN Raise("ctlc")
renderdiffs(s,1024)
UNTIL state<0
EXCEPT DO
IF w THEN CloseWindow(w)
IF s THEN CloseScreen(s)
IF mem AND ((fh:=Open('ram:mem.dump',MODE_NEWFILE))<>NIL)
PrintF('Writing ram:mem.dump\n')
Fwrite(fh,mem,65536,1)
Close(fh)
ENDIF
IF io AND ((fh:=Open('ram:io.dump',MODE_NEWFILE))<>NIL)
PrintF('Writing ram:io.dump\n')
Fwrite(fh,io,4096,1)
Close(fh)
ENDIF
IF mem THEN Dispose(mem)
IF io THEN Dispose(io)
IF kernelrom THEN freefile(kernelrom)
IF basicrom THEN freefile(basicrom)
IF charrom THEN freefile(charrom)
IF size THEN freefile(size)
IF opcodes THEN freefile(opcodes)
SELECT exception
CASE "MEM" ; PrintF('Out of memory!\n')
CASE "OPEN" ; PrintF('Can\at open!\n')
CASE "CHIP" ; PrintF('Out of chip memory!\n')
CASE "kern" ; PrintF('Can\at load kerne roml!\n')
CASE "basi" ; PrintF('Can\at load basic rom!\n')
CASE "char" ; PrintF('Can\at load character rom!\n')
CASE "size" ; PrintF('Can\at load size table!\n')
CASE "time" ; PrintF('Can\at load time table!\n')
CASE "args" ; PrintF('Usage: 6510emu [verbose]\n')
DEFAULT
PrintF('Exiting.\n')
ENDSELECT
ENDPROC
PROC clearscreen(screen:PTR TO screen)
DEF y,dy,i,base,sdata:PTR TO CHAR
sdata:=screen.bitmap.planes[0]+(screen.bitmap.bytesperrow*11)
FOR dy:=0 TO 7
base:=dy*screen.bitmap.bytesperrow
FOR i:=0 TO 41
sdata[base+i]:=255
ENDFOR
ENDFOR
FOR y:=1 TO 25
FOR dy:=0 TO 7
base:=(y*8+dy)*screen.bitmap.bytesperrow
sdata[base]:=255
sdata[base+41]:=255
FOR i:=1 TO 40
sdata[base+i]:=0
ENDFOR
ENDFOR
ENDFOR
FOR dy:=0 TO 7
base:=(208+dy)*screen.bitmap.bytesperrow
FOR i:=0 TO 41
sdata[base+i]:=255
ENDFOR
ENDFOR
ENDPROC
PROC renderscreen(screen:PTR TO screen,charstart)
DEF i
FOR i:=0 TO 24
renderline(screen,i,charstart)
ENDFOR
ENDPROC
PROC renderdiffs(screen:PTR TO screen,charstart)
DEF i
FOR i:=0 TO 24
IF linelist[i]<>0
renderline(screen,i,charstart)
linelist[i]:=0
ENDIF
ENDFOR
ENDPROC
/*
PROC writechar(screen:PTR TO screen,sx,sy,asc)
DEF dy,sdata:PTR TO CHAR
IF ((sx<0) OR (sx>39)) OR ((sy<0) OR (sy>24))
PrintF('X: \d\n',sx)
PrintF('Y: \d\n',sy)
Raise("brk")
ENDIF
sdata:=screen.bitmap.planes[0]+(sx+1)+(((sy+1)*8+11)*screen.bitmap.bytesperrow)
FOR dy:=0 TO 7
sdata[dy*screen.bitmap.bytesperrow]:=charrom[asc*8+dy]
ENDFOR
ENDPROC
*/
PROC renderline(screen:PTR TO screen,sy,charstart)
DEF dx,dy,sdata:PTR TO CHAR,chardata
IF ((sy<0) OR (sy>24))
PrintF('Y: \d\n',sy)
Raise("brk")
ENDIF
chardata:=40*sy+charstart
sdata:=screen.bitmap.planes[0]+1+(((sy+1)*8+11)*screen.bitmap.bytesperrow)
FOR dy:=0 TO 7
FOR dx:=0 TO 39
sdata[dy*screen.bitmap.bytesperrow+dx]:=charrom[mem[chardata+dx]*8+dy]
ENDFOR
ENDFOR
ENDPROC
#define lb(val) (val AND $00ff)
#define hb(val) Shr(val,8)
#define deek(address) ((peek(address+1)*256)+peek(address))
/*
$0000-$9fff $a000-$bfff $c000-$cfff $d000-$dfff $e000-$efff
000 0 ram ram ram ram ram
001 1 ram ram ram char rom ram
010 2 ram ram ram char rom kernel
011 3 ram basic ram char rom kernel
100 4 ram ram ram ram ram
101 5 ram ram ram i/o ram
110 6 ram ram ram i/o kernel
111 7 ram basic ram i/o kernel
*/
PROC peek(address)
DEF i
address:=address AND $ffff
i:=ioport AND 7
SELECT 256 OF hb(address)
CASE $00
IF address=0 THEN RETURN ddr
IF address=1 THEN RETURN ioport
RETURN mem[address]
CASE $01 TO $9f
RETURN mem[address]
CASE $a0 TO $bf
IF (i AND 3)=3 THEN RETURN basicrom[address-$a000]
RETURN mem[address]
CASE $c0 TO $cf
RETURN mem[address]
CASE $d0 TO $d3
IF i>=5 THEN RETURN readvic(address AND $3f)
IF (i AND 3)=0 THEN RETURN mem[address]
RETURN charrom[address-$d000]
CASE $d4 TO $d7
IF i>=5 THEN RETURN readsid(address AND $1f)
IF (i AND 3)=0 THEN RETURN mem[address]
RETURN charrom[address-$d000]
CASE $d8 TO $db
IF i>=5 THEN RETURN (io[address-$d000] AND $0f) OR (RndQ(cyclecount) AND $f0)
IF (i AND 3)=0 THEN RETURN mem[address]
RETURN charrom[address-$d000]
CASE $dc
IF i>=5 THEN RETURN readcia(1,address AND $0f)
IF (i AND 3)=0 THEN RETURN mem[address]
RETURN charrom[address-$d000]
CASE $dd
IF i>=5 THEN RETURN readcia(2,address AND $0f)
IF (i AND 3)=0 THEN RETURN mem[address]
RETURN charrom[address-$d000]
CASE $de TO $df
RETURN RndQ(cyclecount) AND $ff
CASE $e0 TO $ff
IF (i AND 2)=2 THEN RETURN kernelrom[address-$e000]
RETURN mem[address]
ENDSELECT
ENDPROC
PROC poke(address,val)
SELECT 256 OF hb(address)
CASE $00
IF address=0 THEN ddr:=val
IF address=1 THEN ioport:=val
mem[address]:=val
CASE $01 TO $cf
mem[address]:=val
CASE $d0 TO $d3
IF (ioport AND 7)>=5 THEN writevic(address AND $3f,val)
mem[address]:=val
CASE $d4 TO $d7
IF (ioport AND 7)>=5 THEN writesid(address AND $1f,val)
mem[address]:=val
CASE $d8 TO $db
IF (ioport AND 7)>=5 THEN io[address-$d000]:=val
mem[address]:=val
CASE $dc
IF (ioport AND 7)>=5 THEN writecia(1,address AND $0f,val)
mem[address]:=val
CASE $dd
IF (ioport AND 7)>=5 THEN writecia(2,address AND $0f,val)
mem[address]:=val
CASE $e0 TO $ff
mem[address]:=val
ENDSELECT
IF (address>=$0400) AND (address<$07e8) THEN linelist[(address-$400)/40]:=1
ENDPROC val
PROC push(val)
mem[sp+256]:=val
sp:=(sp-1) AND 255
ENDPROC
PROC pull()
DEF val
sp:=(sp+1) AND 255
val:=mem[sp+256]
ENDPROC val
#define setN status:=status OR $80
#define setV status:=status OR $40
#define setB status:=status OR $10
#define setD status:=status OR $08
#define setI status:=status OR $04
#define setZ status:=status OR $02
#define setC status:=status OR $01
#define clrN status:=status AND $7f
#define clrV status:=status AND $bf
#define clrB status:=status AND $ef
#define clrD status:=status AND $f7
#define clrI status:=status AND $fb
#define clrZ status:=status AND $fd
#define clrC status:=status AND $fe
PROC setnz(val)
IF val=0 THEN setZ ELSE clrZ
IF val AND 128 THEN setN ELSE clrN
ENDPROC
PROC incpc(val)
pc:=pc+val
IF val AND 128 THEN pc:=pc-256
pc:=pc AND 65535
ENDPROC
PROC reset()
ioport:=$37
ddr:=$2f
pc:=deek($fffc)
sp:=255
status:=$20
PrintF('Reset: PC $\z\h[4]\n',pc)
ENDPROC
/*
PROC ioread(address)
IF (address>=$d000) AND (address<=$d3ff)
RETURN vicread(address AND 63)
ELSEIF (address>=$d400) AND (address<=$d7ff)
RETURN sidread(address AND 31)
ELSEIF (address>=$d800) AND (address<=$dbff)
RETURN (io[address-$d800] AND 15)+(RndQ(pc*a*x*y*cyclecount) AND 240)
ELSEIF (address>=$dc00) AND (address<=$dcff)
RETURN ciaread(1,address AND 15)
ELSEIF (address>=$dd00) AND (address<=$ddff)
RETURN ciaread(2,address AND 15)
ELSEIF (address>=$de00) AND (address<=$dfff)
RETURN Shl("0156",4*(address AND 3)) AND 255
ELSE
PrintF('ioreading outside io area\n')
Raise("brk")
ENDIF
ENDPROC
*/
/*
PROC iowrite(address,val)
IF (address>=$d000) AND (address<=$dfff)
io[address-$d000]:=val
ELSE
PrintF('iowriting outside io area\n')
Raise("brk")
ENDIF
ENDPROC val
*/
PROC readvic(address)
DEF rasterrow
rasterrow:=Mod(cyclecount,18593)/60
SELECT 64 OF address
CASE $11
RETURN io[address+$d000] AND 127 OR (rasterrow/2 AND 128)
CASE $12
RETURN rasterrow AND 255
CASE $13
RETURN 0
CASE $14
RETURN 0
CASE $19
RETURN 0
CASE $1e
RETURN 0
CASE $1f
RETURN 0
CASE $2f TO $3f
RETURN 0
DEFAULT
RETURN io[address+$d000]
ENDSELECT
ENDPROC
PROC readsid(address) IS io[address+$400]
PROC readcia(chip,address) IS io[address+$db00+(chip*$100)]
PROC writevic(address,val)
io[address]:=val
ENDPROC
PROC writesid(address,val)
io[address+$400]:=val
ENDPROC
PROC writecia(chip,address,val)
io[address+$db00+(chip*$100)]:=val
ENDPROC
PROC emulate()
DEF m,a0,a1,a16,state,tmp
DEF opname[3]:STRING,adrmode[8]:STRING,tmpstring[256]:STRING
IF (pc=$fd68) AND (skipmemtest=1) AND ((ioport AND 3)=3)
PrintF('Skipping memory test\n')
pc:=$fd88
mem[$c1]:=$00
mem[$c2]:=$a0
y:=0
ENDIF
/*
IF (pc=$e5d6) AND (verbose=0)
PrintF('***Reached $\z\h[4]***\n',pc)
verbose:=1
ENDIF
IF (pc=$e5cd) AND (verbose=1)
PrintF('***Reached $\z\h[4]***\n',pc)
verbose:=0
ENDIF
*/
state:=0
m:=peek(pc)
a0:=peek(pc+1)
a1:=peek(pc+2)
a16:=a0+(a1*256)
IF verbose=1
PrintF('\z\h[4] \z\h[2] ',pc,m)
StrCopy(opname,opcodelist[m],3)
MidStr(adrmode,opcodelist[m],3)
IF StrCmp(adrmode,'')
PrintF(' \s\t',opname)
ELSEIF InStr(adrmode,'@3')>=0
tmp:=pc+2+a0
IF a0>127 THEN tmp:=tmp-256
PrintF('\z\h[2] \s $\z\h[4]',a0,opname,tmp AND 65535)
ELSEIF (tmp:=InStr(adrmode,'@2'))>=0
StrCopy(tmpstring,adrmode,tmp)
PrintF('\z\h[2] \z\h[2] \s\s\z\h[4]',a0,a1,opname,tmpstring,a16)
MidStr(tmpstring,adrmode,tmp+4)
PrintF('\s',tmpstring)
ELSEIF (tmp:=InStr(adrmode,'@1'))>=0
StrCopy(tmpstring,adrmode,tmp)
PrintF('\z\h[2] \s\s\z\h[2]',a0,opname,tmpstring,a0)
MidStr(tmpstring,adrmode,tmp+2)
PrintF('\s',tmpstring)
ELSE
PrintF('fucked up adrmode')
ENDIF
IF StrCmp(adrmode,' $@1')=TRUE THEN PrintF('\t')
PrintF('\t A:\z\h[2] X:\z\h[2] Y:\z\h[2] SP:\z\h[2] SR:\z\h[2]\n',a,x,y,sp,status)
ENDIF
SELECT 256 OF m
CASE $00 -> BRK
incpc(2)
push(hb(sp)) ; push(lb(sp))
setB
push(status)
setI
sp:=deek($fffe)
CASE $01 -> ORA ($01,x)
setnz(a:=a OR peek(deek(a0+x)))
CASE $05 -> ORA $01
setnz(a:=a OR peek(a0))
CASE $06 -> ASL $01
poke(a0,asl(peek(a0)))
CASE $08 -> PHP
push(status)
CASE $09 -> ORA #$01
setnz(a:=a OR a0)
CASE $0a -> ASL
a:=asl(a)
CASE $0d -> ORA $0201
setnz(a:=a OR peek(a16))
CASE $0e -> ASL $0201
poke(a16,asl(peek(a16)))
CASE $10 -> BPL
incpc(2)
IF (status AND $80)=0 THEN incpc(a0)
CASE $11 -> ORA ($01),y
setnz(a:=a OR peek(deek(a0)+y))
CASE $15 -> ORA $01,x
setnz(a:=a OR peek(a0+x))
CASE $16 -> ASL $01,x
poke(a0+x,asl(peek(a0+x)))
CASE $18 -> CLC
clrC
CASE $19 -> ORA $0201,y
setnz(a:=a OR peek(a16+y))
CASE $1d -> ORA $0201,x
setnz(a:=a OR peek(a16+x))
CASE $1e -> ASL $0201,x
poke(a16+x,asl(peek(a16+x)))
CASE $20 -> JSR $0201
incpc(3)
push(hb(pc)) ; push(lb(pc))
pc:=a16
CASE $21 -> AND ($01,x)
setnz(a:=a AND peek(deek(a0+x)))
CASE $24 -> BIT $01
bit(peek(a0))
CASE $25 -> AND $01
setnz(a:=a AND peek(a0))
CASE $26 -> ROL $01
poke(a0,rol(peek(a0)))
CASE $28 -> PLP
status:=pull()
CASE $29 -> AND #$01
setnz(a:=a AND a0)
CASE $2a -> ROL
a:=rol(a)
CASE $2c -> BIT $0201
bit(peek(a16))
CASE $2d -> AND $0201
setnz(a:=a AND peek(a16))
CASE $2e -> ROL $0201
poke(a16,rol(peek(a16)))
CASE $30 -> BMI
incpc(2)
IF (status AND $80) THEN incpc(a0)
CASE $31 -> AND ($01),y
setnz(a:=a AND peek(deek(a0)+y))
CASE $35 -> AND $01,x
setnz(a:=a AND peek(a0+x))
CASE $36 -> ROL $01,x
poke(a0+x,rol(peek(a0+x)))
CASE $38 -> SEC
setC
CASE $39 -> AND $0201,y
setnz(a:=a AND peek(a16+y))
CASE $3d -> AND $0201,x
setnz(a:=a AND peek(a16+x))
CASE $3e -> ROL $0201,x
poke(a16+x,rol(peek(a16+x)))
CASE $40 -> RTI
status:=pull()
tmp:=pull()
pc:=pull()*256+tmp
CASE $41 -> EOR ($01,x)
setnz(a:=Eor(a,peek(deek(a0+x))))
CASE $45 -> EOR $01
setnz(a:=Eor(a,peek(a0)))
CASE $46 -> LSR $01
poke(a0,lsr(peek(a0)))
CASE $48 -> PHA
push(a)
CASE $49 -> EOR #$01
setnz(a:=Eor(a,a0))
CASE $4a -> LSR
a:=lsr(a)
CASE $4c -> JMP $0201
pc:=a16
CASE $4d -> EOR $0201
setnz(a:=Eor(a,peek(a16)))
CASE $4e -> LSR $0201
poke(a16,lsr(peek(a16)))
CASE $50 -> BVC
incpc(2)
IF (status AND $40)=0 THEN incpc(a0)
CASE $51 -> EOR ($01),y
setnz(a:=Eor(a,peek(deek(a0)+y)))
CASE $55 -> EOR $01,x
setnz(a:=Eor(a,peek(a0+x)))
CASE $56 -> LSR $01,x
poke(a0+x,lsr(peek(a0+x)))
CASE $58 -> CLI
clrI
CASE $59 -> EOR $0201,y
setnz(a:=Eor(a,peek(a16+y)))
CASE $5d -> EOR $0201,x
setnz(a:=Eor(a,peek(a16+x)))
CASE $5e -> LSR $0201,x
poke(a16+x,lsr(peek(a16+x)))
CASE $60 -> RTS
tmp:=pull()
pc:=pull()*256+tmp
CASE $61 -> ADC ($01,x)
adc(peek(deek(a0+x)))
CASE $65 -> ADC $01
adc(peek(a0))
CASE $66 -> ROR $01
poke(a0,ror(peek(a0)))
CASE $68 -> PLA
a:=pull()
CASE $69 -> ADC #$01
adc(a0)
CASE $6a -> ROR
a:=ror(a)
CASE $6c -> JMP ($0201)
pc:=deek(a16)
CASE $6d -> ADC $0201
adc(peek(a16))
CASE $6e -> ROR $0201
poke(a16,ror(peek(a16)))
CASE $70 -> BVS
incpc(2)
IF (status AND $40) THEN incpc(a0)
CASE $71 -> ADC ($01),y
adc(peek(deek(a0)+y))
CASE $75 -> ADC $01,x
adc(peek(a0+x))
CASE $76 -> ROR $01,x
poke(a0+x,ror(peek(a0+x)))
CASE $78 -> SEI
setI
CASE $79 -> ADC $0201,y
adc(peek(a16+y))
CASE $7d -> ADC $0201,x
adc(peek(a16+x))
CASE $7e -> ROR $0201,x
poke(a16+x,ror(peek(a16+x)))
CASE $81 -> STA ($01,x)
poke(deek(a0+x),a)
CASE $84 -> STY $01
poke(a0,y)
CASE $85 -> STA $01
poke(a0,a)
CASE $86 -> STX $01
poke(a0,x)
CASE $88 -> DEY
setnz(y:=(y-1) AND 255)
CASE $8a -> TXA
setnz(a:=x)
CASE $8c -> STY $0201
poke(a16,y)
CASE $8d -> STA $0201
poke(a16,a)
CASE $8e -> STX $0201
poke(a16,x)
CASE $90 -> BCC
incpc(2)
IF (status AND 1)=0 THEN incpc(a0)
CASE $91 -> STA ($01),y
poke(deek(a0)+y,a)
CASE $94 -> STY $01,x
poke(a0+x,y)
CASE $95 -> STA $01,x
poke(a0+x,a)
CASE $96 -> STX $01,y
poke(a0+y,x)
CASE $98 -> TYA
setnz(a:=y)
CASE $99 -> STA $0201,y
poke(a16+y,a)
CASE $9a -> TXS
sp:=x
CASE $9d -> STA $0201,x
poke(a16+x,a)
CASE $a0 -> LDY #$01
setnz(y:=a0)
CASE $a1 -> LDA ($01,x)
setnz(a:=peek(deek(a0+x)))
CASE $a2 -> LDX #$01
setnz(x:=a0)
CASE $a4 -> LDY $01
setnz(y:=peek(a0))
CASE $a5 -> LDA $01
setnz(a:=peek(a0))
CASE $a6 -> LDX $01
setnz(x:=peek(a0))
CASE $a8 -> TAY
setnz(y:=a)
CASE $a9 -> LDA #$01
setnz(a:=a0)
CASE $aa -> TAX
setnz(x:=a)
CASE $ac -> LDY $0201
setnz(y:=peek(a16))
CASE $ad -> LDA $0201
setnz(a:=peek(a16))
CASE $ae -> LDX $0201
setnz(x:=peek(a16))
CASE $b0 -> BCS
incpc(2)
IF (status AND 1) THEN incpc(a0)
CASE $b1 -> LDA ($01),y
setnz(a:=peek(deek(a0)+y))
CASE $b4 -> LDY $01,x
setnz(y:=peek(a0+x))
CASE $b5 -> LDA $01,x
setnz(a:=peek(a0+x))
CASE $b6 -> LDX $01,y
setnz(x:=peek(a0+y))
CASE $b8 -> CLV
clrV
CASE $b9 -> LDA $0201,y
setnz(a:=peek(a16+y))
CASE $ba -> TSX
setnz(x:=sp)
CASE $bc -> LDY $0201,x
setnz(y:=peek(a16+x))
CASE $bd -> LDA $0201,x
setnz(a:=peek(a16+x))
CASE $be -> LDX $0201,y
setnz(x:=peek(a16+y))
CASE $c0 -> CPY #$01
cmp(y,a0)
CASE $c1 -> CMP ($01,x)
cmp(a,peek(deek(a0+x)))
CASE $c4 -> CPY $01
cmp(y,peek(a0))
CASE $c5 -> CMP $01
cmp(a,peek(a0))
CASE $c6 -> DEC $01
setnz(poke(a0,(peek(a0)-1) AND 255))
CASE $c8 -> INY
setnz(y:=(y+1) AND 255)
CASE $c9 -> CMP #$01
cmp(a,a0)
CASE $ca -> DEX
setnz(x:=(x-1) AND 255)
CASE $cc -> CPY $0201
cmp(y,peek(a16))
CASE $cd -> CMP $0201
cmp(a,peek(a16))
CASE $ce -> DEC $0201
setnz(poke(a16,(peek(a16)-1) AND 255))
CASE $d0 -> BNE
incpc(2)
IF (status AND $02)=0 THEN incpc(a0)
CASE $d1 -> CMP ($01),y
cmp(a,peek(deek(a0)+y))
CASE $d5 -> CMP $01,x
cmp(a,peek(a0+x))
CASE $d6 -> DEC $01,x
setnz(poke(a0+x,(peek(a0+x)-1) AND 255))
CASE $d8 -> CLD
clrD
CASE $d9 -> CMP $0201,y
cmp(a,peek(a16+y))
CASE $dd -> CMP $0201,x
cmp(a,peek(a16+x))
CASE $de -> DEC $0201,x
setnz(poke(a16+x,(peek(a16+x)-1) AND 255))
CASE $e0 -> CPX #$01
cmp(x,a0)
CASE $e1 -> SBC ($01,x)
sbc(peek(deek(a0+x)))
CASE $e4 -> CPX $01
cmp(x,peek(a0))
CASE $e5 -> SBC $01
sbc(peek(a0))
CASE $e6 -> INC $01
setnz(poke(a0,(peek(a0)+1) AND 255))
CASE $e8 -> INX
setnz(x:=(x+1) AND 255)
CASE $e9 -> SBC #$01
sbc(a0)
CASE $ea -> NOP
-> NOP :)
CASE $ec -> CPX $0201
cmp(x,peek(a16))
CASE $ed -> SBC $0201
sbc(peek(a16))
CASE $ee -> INC $0201
setnz(poke(a16,(peek(a16)+1) AND 255))
CASE $f0 -> BEQ
incpc(2)
IF (status AND $02) THEN incpc(a0)
CASE $f1 -> SBC ($01),y
sbc(peek(deek(a0)+y))
CASE $f5 -> SBC $01,x
sbc(peek(a0+x))
CASE $f6 -> INC $01,x
setnz(poke(a0+x,(peek(a0+x)+1) AND 255))
CASE $f8 -> SED
setD
CASE $f9 -> SBC $0201,y
sbc(peek(a16+y))
CASE $fd -> SBC $0201,x
sbc(peek(a16+x))
CASE $fe -> INC $0201,x
setnz(poke(a16+x,(peek(a16+x)+1) AND 255))
DEFAULT
state:=1
ENDSELECT
incpc(size[m])
cyclecount:=cyclecount+time[m]
ENDPROC state
PROC bit(val)
IF a AND val THEN clrZ ELSE setZ
IF val AND 128 THEN setN ELSE clrN
IF val AND 64 THEN setV ELSE clrV
ENDPROC
PROC asl(val)
val:=Shl(val,1)
IF val>255 THEN setC ELSE clrC
val:=val AND 255
setnz(val)
ENDPROC val
PROC lsr(val)
IF val AND 1 THEN setC ELSE clrC
val:=Shr(val,1)
setnz(val)
ENDPROC val
PROC rol(val)
DEF tmp
tmp:=(status AND 1)
val:=tmp OR asl(val)
ENDPROC val
PROC ror(val)
DEF tmp
tmp:=(status AND 1)
IF val AND 1 THEN setC ELSE clrC
val:=Shr(val,1) OR (tmp*128)
setnz(val)
ENDPROC val
PROC adc(val) -> finally working!
DEF tmp
IF (status AND $08) THEN PrintF('No decimal mode emulation - doing binary ADC\n')
tmp:=a
a:=a+val+(status AND 1)
IF a>255
setC
a:=a AND 255
ELSE
clrC
ENDIF
setnz(a)
IF (tmp<$80) AND (val<$80) AND (a>=$80)
setV
ELSEIF (tmp>=$80) AND (val>=$80) AND (a<$80)
setV
ELSE
clrV
ENDIF
ENDPROC
PROC sbc(val)
DEF tmp
IF (status AND $08) THEN PrintF('No decimal mode emulation - doing binary SBC\n')
tmp:=a
a:=a-val+(status AND 1)-1
IF a<0
clrC
a:=a AND 255
ELSE
setC
ENDIF
setnz(a)
IF (tmp<$80) AND (val>=$80) AND (a>=$80)
setV
ELSEIF (tmp>=$80) AND (val<$80) AND (a<$80)
setV
ELSE
clrV
ENDIF
ENDPROC
PROC cmp(t1,t2) -> ugh, fix the kludge
DEF tmp
tmp:=t1-t2
IF tmp<0
clrC
tmp:=tmp AND 255
ELSE
setC
ENDIF
setnz(tmp)
ENDPROC
-> 6510 object
OPT PREPROCESS
OBJECT proc6510
a:CHAR
x:CHAR
y:CHAR
sp:CHAR
pc:WORD
/* 84218421 */
/* NV#BDIZC */
status:CHAR
ioport:CHAR
ddr:CHAR
PRIVATE
peek:PTR TO LONG
poke:PTR TO LONG
resetState:CHAR
nmiState:CHAR
irqState:CHAR
ENDOBJECT
PROC start(pokefunc,peekfunc) OF proc6510
self.peek:=peekfunc
self.poke:=pokefunc
self.reset()
ENDPROC
PROC reset() OF proc6510
self.ioport:=$37
self.ddr:=$2f
self.pc:=self.deek($fffc)
self.sp:=255
self.status:=$20
self.a:=0
self.x:=0
self.y:=0
self.resetcycles()
self.resetState:=FALSE
self.nmiState:=FALSE
self.irqState:=FALSE
ENDPROC
PROC nmi() OF proc6510
push(hb(self.pc)) ; push(lb(self.pc))
push(self.status)
self.pc:=deek($fffa)
self.addcycles(7)
self.nmiState:=FALSE
self.irqState:=FALSE
ENDPROC
PROC irq() OF proc6510
push(hb(self.pc)) ; push(lb(self.pc))
push(self.status)
self.pc:=deek($fffe)
self.addcycles(7)
self.irqState:=FALSE
ENDPROC
PROC emulate() OF proc6510
DEF state=0
ENDPROC state
$ hexdump 6510SIZE.TAB
0000000 01 02 01 02 02 02 02 02 01 02 01 01 03 03 03 03
0000010 00 02 01 02 02 02 02 02 01 03 01 03 02 03 03 03
0000020 00 02 01 02 02 02 02 02 01 02 01 01 03 03 03 03
0000030 00 02 01 02 02 02 02 02 01 03 01 03 03 03 03 03
0000040 00 02 01 02 02 02 02 02 01 02 01 01 00 03 03 03
0000050 00 02 01 02 02 02 02 02 01 03 01 03 03 03 03 03
0000060 00 02 01 02 02 02 02 02 01 02 01 01 00 03 03 03
0000070 00 02 01 02 02 02 02 02 01 03 01 03 03 03 03 03
0000080 02 02 02 02 02 02 02 02 01 02 01 02 03 03 03 03
0000090 00 02 01 03 02 02 02 02 01 03 01 03 03 03 03 03
00000a0 02 02 02 02 02 02 02 02 01 02 01 01 03 03 03 03
00000b0 00 02 01 02 02 02 02 02 01 03 01 03 03 03 03 03
00000c0 02 02 02 02 02 02 02 02 01 02 01 02 03 03 03 03
00000d0 00 02 01 02 02 02 02 02 01 03 01 03 03 03 03 03
00000e0 02 02 02 03 02 02 02 02 01 02 01 01 03 03 03 03
00000f0 00 02 01 02 02 02 02 02 01 03 01 03 03 03 03 03
0000100
$ hexdump -v 6510TIME.TAB
0000000 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
0000010 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
0000020 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
0000030 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
0000040 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
0000050 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
0000060 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
0000070 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
0000080 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
0000090 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
00000a0 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
00000b0 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
00000c0 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
00000d0 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
00000e0 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
00000f0 74 6a 6f 73 61 6e 74 6a 6f 73 61 6e 74 6a 6f 0a
0000100
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment