mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-02-23 03:29:05 +00:00
williams: added test for 6809; fiddled with atari7800
This commit is contained in:
parent
4dfab17e7b
commit
4d5c6b9063
@ -171,7 +171,10 @@ TODO:
|
||||
- popup
|
||||
- convert binary to hex stmts
|
||||
- "suggestions" (vblank overrun, variable # scanlines, etc)
|
||||
- spinner doesn't always spin on sms
|
||||
- SMS
|
||||
- can't step back twice?
|
||||
- compiler bug in chase
|
||||
|
||||
|
||||
WEB WORKER FORMAT
|
||||
|
||||
|
@ -1,440 +1,443 @@
|
||||
; Atari 7800 sprite sample
|
||||
; Written by Daniel Boris (dboris@home.com)
|
||||
;
|
||||
; Assemble with DASM
|
||||
;
|
||||
|
||||
processor 6502
|
||||
|
||||
; ************ Hardware Adresses ***************************
|
||||
|
||||
INPTCTRL equ $01 ;Input control
|
||||
AUDC0 equ $15 ;Audio Control Channel 0
|
||||
AUDC1 equ $16 ;Audio Control Channel 1
|
||||
AUDF0 equ $17 ;Audio Frequency Channel 0
|
||||
AUDF1 equ $18 ;Audio Frequency Channel 1
|
||||
AUDV0 equ $19 ;Audio Volume Channel 0
|
||||
AUDV1 equ $1A ;Audio Volume Channel 1
|
||||
INPT0 equ $08 ;Paddle Control Input 0
|
||||
INPT1 equ $09 ;Paddle Control Input 1
|
||||
INPT2 equ $0A ;Paddle Control Input 2
|
||||
INPT3 equ $0B ;Paddle Control Input 3
|
||||
INPT4 equ $0C ;Player 0 Fire Button Input
|
||||
INPT5 equ $0D ;Player 1 Fire Button Input
|
||||
|
||||
BACKGRND equ $20 ;Background Color
|
||||
P0C1 equ $21 ;Palette 0 - Color 1
|
||||
P0C2 equ $22 ;Palette 0 - Color 2
|
||||
P0C3 equ $23 ;Palette 0 - Color 3
|
||||
WSYNC equ $20 ;Wait For Sync
|
||||
P1C1 equ $21 ;Palette 1 - Color 1
|
||||
P1C2 equ $22 ;Palette 1 - Color 2
|
||||
P1C3 equ $23 ;Palette 1 - Color 3
|
||||
MSTAT equ $28 ;Maria Status
|
||||
P2C1 equ $29 ;Palette 2 - Color 1
|
||||
P2C2 equ $2A ;Palette 2 - Color 2
|
||||
P2C3 equ $2B ;Palette 2 - Color 3
|
||||
DPPH equ $2C ;Display List List Pointer High
|
||||
P3C1 equ $2D ;Palette 3 - Color 1
|
||||
P3C2 equ $2E ;Palette 3 - Color 2
|
||||
P3C3 equ $2F ;Palette 3 - Color 3
|
||||
DPPL equ $30 ;Display List List Pointer Low
|
||||
P4C1 equ $31 ;Palette 4 - Color 1
|
||||
P4C2 equ $32 ;Palette 4 - Color 2
|
||||
P4C3 equ $33 ;Palette 4 - Color 3
|
||||
CHARBASE equ $34 ;Character Base Address
|
||||
P5C1 equ $35 ;Palette 5 - Color 1
|
||||
P5C2 equ $36 ;Palette 5 - Color 2
|
||||
P5C3 equ $37 ;Palette 5 - Color 3
|
||||
OFFSET equ $38 ;Unused - Store zero here
|
||||
P6C1 equ $39 ;Palette 6 - Color 1
|
||||
P6C2 equ $3A ;Palette 6 - Color 2
|
||||
P6C3 equ $3B ;Palette 6 - Color 3
|
||||
CTRL equ $3C ;Maria Control Register
|
||||
P7C1 equ $3D ;Palette 7 - Color 1
|
||||
P7C2 equ $3E ;Palette 7 - Color 2
|
||||
P7C3 equ $3F ;Palette 7 - Color 3
|
||||
|
||||
SWCHA equ $280 ;P0, P1 Joystick Directional Input
|
||||
SWCHB equ $282 ;Console Switches
|
||||
CTLSWA equ $281 ;I/O Control for SCHWA
|
||||
CTLSWB equ $283 ;I/O Control for SCHWB
|
||||
|
||||
SEG.U data
|
||||
|
||||
|
||||
;******* Vairables ********************************
|
||||
|
||||
org $40
|
||||
|
||||
xpos ds.b 1 ;X Position of sprite
|
||||
ypos ds.b 1 ;Y Position of sprite
|
||||
temp ds.b 1
|
||||
dlpnt ds.w 1
|
||||
dlend ds.b 12 ;Index of end of each DL
|
||||
|
||||
|
||||
|
||||
|
||||
;**********************************************************
|
||||
|
||||
SEG code
|
||||
|
||||
org $4000 ;Start of code
|
||||
|
||||
START
|
||||
sei ;Disable interrupts
|
||||
cld ;Clear decimal mode
|
||||
|
||||
|
||||
;******** Atari recommended startup procedure
|
||||
|
||||
lda #$07
|
||||
sta INPTCTRL ;Lock into 7800 mode
|
||||
lda #$7F
|
||||
sta CTRL ;Disable DMA
|
||||
lda #$00
|
||||
sta OFFSET
|
||||
sta INPTCTRL
|
||||
ldx #$FF ;Reset stack pointer
|
||||
txs
|
||||
|
||||
;************** Clear zero page and hardware ******
|
||||
|
||||
ldx #$40
|
||||
lda #$00
|
||||
crloop1
|
||||
sta $00,x ;Clear zero page
|
||||
sta $100,x ;Clear page 1
|
||||
inx
|
||||
bne crloop1
|
||||
|
||||
;************* Clear RAM **************************
|
||||
|
||||
ldy #$00 ;Clear Ram
|
||||
lda #$18 ;Start at $1800
|
||||
sta $81
|
||||
lda #$00
|
||||
sta $80
|
||||
crloop3
|
||||
lda #$00
|
||||
sta ($80),y ;Store data
|
||||
iny ;Next byte
|
||||
bne crloop3 ;Branch if not done page
|
||||
inc $81 ;Next page
|
||||
lda $81
|
||||
cmp #$20 ;End at $1FFF
|
||||
bne crloop3 ;Branch if not
|
||||
|
||||
ldy #$00 ;Clear Ram
|
||||
lda #$22 ;Start at $2200
|
||||
sta $81
|
||||
lda #$00
|
||||
sta $80
|
||||
crloop4
|
||||
lda #$00
|
||||
sta ($80),y ;Store data
|
||||
iny ;Next byte
|
||||
bne crloop4 ;Branch if not done page
|
||||
inc $81 ;Next page
|
||||
lda $81
|
||||
cmp #$27 ;End at $27FF
|
||||
bne crloop4 ;Branch if not
|
||||
|
||||
ldx #$00
|
||||
lda #$00
|
||||
crloop5 ;Clear 2100-213F
|
||||
sta $2100,x
|
||||
inx
|
||||
cpx #$40
|
||||
bne crloop5
|
||||
|
||||
;************* Build DLL *******************
|
||||
|
||||
; 20 blank lines
|
||||
|
||||
ldx #$00
|
||||
lda #$4F ;16 lines
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$21 ;$2100 = blank DL
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$00
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$44 ;4 lines
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$21
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$00
|
||||
sta $1800,x
|
||||
inx
|
||||
|
||||
; 192 mode lines divided into 12 regions
|
||||
|
||||
ldy #$00
|
||||
DLLloop2
|
||||
lda #$4F ;16 lines
|
||||
sta $1800,x
|
||||
inx
|
||||
lda DLPOINTH,y
|
||||
sta $1800,x
|
||||
inx
|
||||
lda DLPOINTL,y
|
||||
sta $1800,x
|
||||
inx
|
||||
iny
|
||||
cpy #$0D ;12 DLL entries
|
||||
bne DLLloop2
|
||||
|
||||
|
||||
; 26 blank lines
|
||||
|
||||
lda #$4F ;16 lines
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$21 ;$2100 = blank DL
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$00
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$4A ;10 lines
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$21
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$00
|
||||
sta $1800,x
|
||||
|
||||
|
||||
;***************** Setup Maria Registers ****************
|
||||
|
||||
lda #$18 ;DLL at $1800
|
||||
sta DPPH
|
||||
lda #$00
|
||||
sta DPPL
|
||||
lda #$18 ;Setup Palette 0
|
||||
sta P0C1
|
||||
lda #$38
|
||||
sta P0C2
|
||||
lda #$58
|
||||
sta P0C3
|
||||
lda #$43 ;Enable DMA
|
||||
sta CTRL
|
||||
lda #$00 ;Setup ports to read mode
|
||||
sta CTLSWA
|
||||
sta CTLSWB
|
||||
|
||||
lda #$40 ;Set initial X position of sprite
|
||||
sta xpos
|
||||
|
||||
mainloop
|
||||
lda MSTAT ;Wait for VBLANK
|
||||
and #$80
|
||||
beq mainloop
|
||||
|
||||
lda SWCHA ;Read stick
|
||||
and #$80 ;Pushed Right?
|
||||
bne skip1
|
||||
ldx xpos ;Move sprite to right
|
||||
inx
|
||||
stx xpos
|
||||
skip1
|
||||
lda SWCHA ;Read stick
|
||||
and #$40 ;Pushed Left?
|
||||
bne skip2
|
||||
ldx xpos ;Move sprite to left
|
||||
dex
|
||||
stx xpos
|
||||
skip2
|
||||
lda SWCHA ;Read stick
|
||||
and #$20 ;Pushed Down?
|
||||
bne skip3
|
||||
ldx ypos ;Move sprite down
|
||||
cpx #176
|
||||
beq skip3 ;Don't move if we are at the bottom
|
||||
inx
|
||||
stx ypos
|
||||
skip3
|
||||
lda SWCHA ;Read stick
|
||||
and #$10 ;Pushed Up?
|
||||
bne skip4
|
||||
ldx ypos ;Move sprite up
|
||||
beq skip4 ;Don't move if we are at the top
|
||||
dex
|
||||
stx ypos
|
||||
skip4
|
||||
|
||||
;********************** reset DL ends ******************
|
||||
|
||||
ldx #$0C
|
||||
lda #$00
|
||||
dlclearloop
|
||||
dex
|
||||
sta dlend,x
|
||||
bne dlclearloop
|
||||
|
||||
|
||||
;******************** build DL entries *********************
|
||||
|
||||
lda ypos ;Get Y position
|
||||
and #$F0
|
||||
lsr ;Divide by 16
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
tax
|
||||
lda DLPOINTL,x ;Get pointer to DL that this sprite starts in
|
||||
sta dlpnt
|
||||
lda DLPOINTH,x
|
||||
sta dlpnt+1
|
||||
|
||||
;Create DL entry for upper part of sprite
|
||||
|
||||
ldy dlend,x ;Get the index to the end of this DL
|
||||
lda #$00
|
||||
sta (dlpnt),y ;Low byte of data address
|
||||
iny
|
||||
lda #$40 ;Mode 320x1
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda ypos
|
||||
and #$0F
|
||||
ora #$a0
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda #$1F ;Palette 0, 1 byte wide
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda xpos ;Horizontal position
|
||||
sta (dlpnt),y
|
||||
sty dlend,x
|
||||
|
||||
lda ypos
|
||||
and #$0F ;See if sprite is entirely within this region
|
||||
beq doneDL ;branch if it is
|
||||
|
||||
;Create DL entry for lower part of sprite
|
||||
|
||||
inx ;Next region
|
||||
lda DLPOINTL,x ;Get pointer to next DL
|
||||
sta dlpnt
|
||||
lda DLPOINTH,x
|
||||
sta dlpnt+1
|
||||
ldy dlend,x ;Get the index to the end of this DL
|
||||
lda #$00
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda #$40 ;Mode 320x1
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda ypos
|
||||
and #$0F
|
||||
eor #$0F
|
||||
sta temp
|
||||
lda #$a0
|
||||
clc
|
||||
sbc temp
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda #$1F ;Palette 0, 1 byte wide
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda xpos ;Horizontal position
|
||||
sta (dlpnt),y
|
||||
sty dlend,x
|
||||
doneDL
|
||||
|
||||
;************** add DL end entry on each DL *****************************
|
||||
|
||||
ldx #$0C
|
||||
dlendloop
|
||||
dex
|
||||
lda DLPOINTL,x
|
||||
sta dlpnt
|
||||
lda DLPOINTH,x
|
||||
sta dlpnt+1
|
||||
ldy dlend,x
|
||||
iny
|
||||
lda #$00
|
||||
sta (dlpnt),y
|
||||
txa
|
||||
bne dlendloop
|
||||
|
||||
vbloop
|
||||
lda MSTAT ;Wait for VBLANK to end
|
||||
and #$80
|
||||
bne vbloop
|
||||
|
||||
jmp mainloop ;Loop
|
||||
|
||||
redraw
|
||||
|
||||
|
||||
NMI
|
||||
RTI
|
||||
|
||||
IRQ
|
||||
RTI
|
||||
|
||||
|
||||
;Pointers to the DLs
|
||||
|
||||
DLPOINTH
|
||||
.byte $22,$22,$22,$22,$23,$23,$23,$23,$24,$24,$24,$24
|
||||
DLPOINTL
|
||||
.byte $00,$40,$80,$C0,$00,$40,$80,$C0,$00,$40,$80,$C0
|
||||
|
||||
|
||||
|
||||
|
||||
;************** Graphic Data *****************************
|
||||
org $a000
|
||||
.byte %00111100
|
||||
org $a100
|
||||
.byte %00111100
|
||||
org $a200
|
||||
.byte %01000010
|
||||
org $a300
|
||||
.byte %01000010
|
||||
org $a400
|
||||
.byte %10011001
|
||||
org $a500
|
||||
.byte %10011001
|
||||
org $a600
|
||||
.byte %10100101
|
||||
org $a700
|
||||
.byte %10100101
|
||||
org $a800
|
||||
.byte %10000001
|
||||
org $a900
|
||||
.byte %10000001
|
||||
org $aA00
|
||||
.byte %10100101
|
||||
org $aB00
|
||||
.byte %10100101
|
||||
org $aC00
|
||||
.byte %01000010
|
||||
org $aD00
|
||||
.byte %01000010
|
||||
org $aE00
|
||||
.byte %00111100
|
||||
org $aF00
|
||||
.byte %00111100
|
||||
|
||||
|
||||
;************** Cart reset vector **************************
|
||||
|
||||
org $fff8
|
||||
.byte $FF ;Region verification
|
||||
.byte $87 ;ROM start $4000
|
||||
.word #NMI
|
||||
.word #START
|
||||
.word #IRQ
|
||||
|
||||
|
||||
; Atari 7800 sprite sample
|
||||
; Written by Daniel Boris (dboris@home.com)
|
||||
;
|
||||
; Assemble with DASM
|
||||
;
|
||||
|
||||
processor 6502
|
||||
|
||||
; ************ Hardware Adresses ***************************
|
||||
|
||||
INPTCTRL equ $01 ;Input control
|
||||
AUDC0 equ $15 ;Audio Control Channel 0
|
||||
AUDC1 equ $16 ;Audio Control Channel 1
|
||||
AUDF0 equ $17 ;Audio Frequency Channel 0
|
||||
AUDF1 equ $18 ;Audio Frequency Channel 1
|
||||
AUDV0 equ $19 ;Audio Volume Channel 0
|
||||
AUDV1 equ $1A ;Audio Volume Channel 1
|
||||
INPT0 equ $08 ;Paddle Control Input 0
|
||||
INPT1 equ $09 ;Paddle Control Input 1
|
||||
INPT2 equ $0A ;Paddle Control Input 2
|
||||
INPT3 equ $0B ;Paddle Control Input 3
|
||||
INPT4 equ $0C ;Player 0 Fire Button Input
|
||||
INPT5 equ $0D ;Player 1 Fire Button Input
|
||||
|
||||
BACKGRND equ $20 ;Background Color
|
||||
P0C1 equ $21 ;Palette 0 - Color 1
|
||||
P0C2 equ $22 ;Palette 0 - Color 2
|
||||
P0C3 equ $23 ;Palette 0 - Color 3
|
||||
WSYNC equ $20 ;Wait For Sync
|
||||
P1C1 equ $21 ;Palette 1 - Color 1
|
||||
P1C2 equ $22 ;Palette 1 - Color 2
|
||||
P1C3 equ $23 ;Palette 1 - Color 3
|
||||
MSTAT equ $28 ;Maria Status
|
||||
P2C1 equ $29 ;Palette 2 - Color 1
|
||||
P2C2 equ $2A ;Palette 2 - Color 2
|
||||
P2C3 equ $2B ;Palette 2 - Color 3
|
||||
DPPH equ $2C ;Display List List Pointer High
|
||||
P3C1 equ $2D ;Palette 3 - Color 1
|
||||
P3C2 equ $2E ;Palette 3 - Color 2
|
||||
P3C3 equ $2F ;Palette 3 - Color 3
|
||||
DPPL equ $30 ;Display List List Pointer Low
|
||||
P4C1 equ $31 ;Palette 4 - Color 1
|
||||
P4C2 equ $32 ;Palette 4 - Color 2
|
||||
P4C3 equ $33 ;Palette 4 - Color 3
|
||||
CHARBASE equ $34 ;Character Base Address
|
||||
P5C1 equ $35 ;Palette 5 - Color 1
|
||||
P5C2 equ $36 ;Palette 5 - Color 2
|
||||
P5C3 equ $37 ;Palette 5 - Color 3
|
||||
OFFSET equ $38 ;Unused - Store zero here
|
||||
P6C1 equ $39 ;Palette 6 - Color 1
|
||||
P6C2 equ $3A ;Palette 6 - Color 2
|
||||
P6C3 equ $3B ;Palette 6 - Color 3
|
||||
CTRL equ $3C ;Maria Control Register
|
||||
P7C1 equ $3D ;Palette 7 - Color 1
|
||||
P7C2 equ $3E ;Palette 7 - Color 2
|
||||
P7C3 equ $3F ;Palette 7 - Color 3
|
||||
|
||||
SWCHA equ $280 ;P0, P1 Joystick Directional Input
|
||||
SWCHB equ $282 ;Console Switches
|
||||
CTLSWA equ $281 ;I/O Control for SCHWA
|
||||
CTLSWB equ $283 ;I/O Control for SCHWB
|
||||
|
||||
SEG.U data
|
||||
|
||||
|
||||
;******* Vairables ********************************
|
||||
|
||||
org $40
|
||||
|
||||
xpos ds.b 1 ;X Position of sprite
|
||||
ypos ds.b 1 ;Y Position of sprite
|
||||
temp ds.b 1
|
||||
dlpnt ds.w 1
|
||||
dlend ds.b 12 ;Index of end of each DL
|
||||
|
||||
|
||||
|
||||
|
||||
;**********************************************************
|
||||
|
||||
SEG code
|
||||
|
||||
org $4000 ;Start of code
|
||||
|
||||
START
|
||||
sei ;Disable interrupts
|
||||
cld ;Clear decimal mode
|
||||
|
||||
|
||||
;******** Atari recommended startup procedure
|
||||
|
||||
lda #$07
|
||||
sta INPTCTRL ;Lock into 7800 mode
|
||||
lda #$7F
|
||||
sta CTRL ;Disable DMA
|
||||
lda #$00
|
||||
sta OFFSET
|
||||
sta INPTCTRL
|
||||
ldx #$FF ;Reset stack pointer
|
||||
txs
|
||||
|
||||
;************** Clear zero page and hardware ******
|
||||
|
||||
ldx #$40
|
||||
lda #$00
|
||||
crloop1
|
||||
sta $00,x ;Clear zero page
|
||||
sta $100,x ;Clear page 1
|
||||
inx
|
||||
bne crloop1
|
||||
|
||||
;************* Clear RAM **************************
|
||||
|
||||
ldy #$00 ;Clear Ram
|
||||
lda #$18 ;Start at $1800
|
||||
sta $81
|
||||
lda #$00
|
||||
sta $80
|
||||
crloop3
|
||||
lda #$00
|
||||
sta ($80),y ;Store data
|
||||
iny ;Next byte
|
||||
bne crloop3 ;Branch if not done page
|
||||
inc $81 ;Next page
|
||||
lda $81
|
||||
cmp #$20 ;End at $1FFF
|
||||
bne crloop3 ;Branch if not
|
||||
|
||||
ldy #$00 ;Clear Ram
|
||||
lda #$22 ;Start at $2200
|
||||
sta $81
|
||||
lda #$00
|
||||
sta $80
|
||||
crloop4
|
||||
lda #$00
|
||||
sta ($80),y ;Store data
|
||||
iny ;Next byte
|
||||
bne crloop4 ;Branch if not done page
|
||||
inc $81 ;Next page
|
||||
lda $81
|
||||
cmp #$27 ;End at $27FF
|
||||
bne crloop4 ;Branch if not
|
||||
|
||||
ldx #$00
|
||||
lda #$00
|
||||
crloop5 ;Clear 2100-213F
|
||||
sta $2100,x
|
||||
inx
|
||||
cpx #$40
|
||||
bne crloop5
|
||||
|
||||
;************* Build DLL *******************
|
||||
|
||||
; 20 blank lines
|
||||
|
||||
ldx #$00
|
||||
lda #$4F ;16 lines
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$21 ;$2100 = blank DL
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$00
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$44 ;4 lines
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$21
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$00
|
||||
sta $1800,x
|
||||
inx
|
||||
|
||||
; 192 mode lines divided into 12 regions
|
||||
|
||||
ldy #$00
|
||||
DLLloop2
|
||||
lda #$4F ;16 lines
|
||||
sta $1800,x
|
||||
inx
|
||||
lda DLPOINTH,y
|
||||
sta $1800,x
|
||||
inx
|
||||
lda DLPOINTL,y
|
||||
sta $1800,x
|
||||
inx
|
||||
iny
|
||||
cpy #$0D ;12 DLL entries
|
||||
bne DLLloop2
|
||||
|
||||
|
||||
; 26 blank lines
|
||||
|
||||
lda #$4F ;16 lines
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$21 ;$2100 = blank DL
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$00
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$4A ;10 lines
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$21
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$00
|
||||
sta $1800,x
|
||||
|
||||
|
||||
;***************** Setup Maria Registers ****************
|
||||
|
||||
lda #$80
|
||||
sta BACKGRND ;background color
|
||||
lda #$18 ;DLL at $1800
|
||||
sta DPPH
|
||||
lda #$00
|
||||
sta DPPL
|
||||
lda #$18 ;Setup Palette 0
|
||||
sta P0C1
|
||||
lda #$38
|
||||
sta P0C2
|
||||
lda #$58
|
||||
sta P0C3
|
||||
lda #$43 ;Enable DMA
|
||||
sta CTRL
|
||||
lda #$00 ;Setup ports to read mode
|
||||
sta CTLSWA
|
||||
sta CTLSWB
|
||||
|
||||
lda #$40 ;Set initial X position of sprite
|
||||
sta xpos
|
||||
|
||||
mainloop
|
||||
lda MSTAT ;Wait for VBLANK
|
||||
and #$80
|
||||
beq mainloop
|
||||
|
||||
lda SWCHA ;Read stick
|
||||
and #$80 ;Pushed Right?
|
||||
bne skip1
|
||||
ldx xpos ;Move sprite to right
|
||||
inx
|
||||
stx xpos
|
||||
skip1
|
||||
lda SWCHA ;Read stick
|
||||
and #$40 ;Pushed Left?
|
||||
bne skip2
|
||||
ldx xpos ;Move sprite to left
|
||||
dex
|
||||
stx xpos
|
||||
skip2
|
||||
lda SWCHA ;Read stick
|
||||
and #$20 ;Pushed Down?
|
||||
bne skip3
|
||||
ldx ypos ;Move sprite down
|
||||
cpx #176
|
||||
beq skip3 ;Don't move if we are at the bottom
|
||||
inx
|
||||
stx ypos
|
||||
skip3
|
||||
lda SWCHA ;Read stick
|
||||
and #$10 ;Pushed Up?
|
||||
bne skip4
|
||||
ldx ypos ;Move sprite up
|
||||
beq skip4 ;Don't move if we are at the top
|
||||
dex
|
||||
stx ypos
|
||||
skip4
|
||||
|
||||
;********************** reset DL ends ******************
|
||||
|
||||
ldx #$0C
|
||||
lda #$00
|
||||
dlclearloop
|
||||
dex
|
||||
sta dlend,x
|
||||
bne dlclearloop
|
||||
|
||||
|
||||
;******************** build DL entries *********************
|
||||
|
||||
lda ypos ;Get Y position
|
||||
and #$F0
|
||||
lsr ;Divide by 16
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
tax
|
||||
lda DLPOINTL,x ;Get pointer to DL that this sprite starts in
|
||||
sta dlpnt
|
||||
lda DLPOINTH,x
|
||||
sta dlpnt+1
|
||||
|
||||
;Create DL entry for upper part of sprite
|
||||
|
||||
ldy dlend,x ;Get the index to the end of this DL
|
||||
lda #$00
|
||||
sta (dlpnt),y ;Low byte of data address
|
||||
iny
|
||||
lda #$40 ;Mode 320x1
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda ypos
|
||||
and #$0F
|
||||
ora #$a0
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda #$1F ;Palette 0, 1 byte wide
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda xpos ;Horizontal position
|
||||
sta (dlpnt),y
|
||||
sty dlend,x
|
||||
|
||||
lda ypos
|
||||
and #$0F ;See if sprite is entirely within this region
|
||||
beq doneDL ;branch if it is
|
||||
|
||||
;Create DL entry for lower part of sprite
|
||||
|
||||
inx ;Next region
|
||||
lda DLPOINTL,x ;Get pointer to next DL
|
||||
sta dlpnt
|
||||
lda DLPOINTH,x
|
||||
sta dlpnt+1
|
||||
ldy dlend,x ;Get the index to the end of this DL
|
||||
lda #$00
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda #$40 ;Mode 320x1
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda ypos
|
||||
and #$0F
|
||||
eor #$0F
|
||||
sta temp
|
||||
lda #$a0
|
||||
clc
|
||||
sbc temp
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda #$1F ;Palette 0, 1 byte wide
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda xpos ;Horizontal position
|
||||
sta (dlpnt),y
|
||||
sty dlend,x
|
||||
doneDL
|
||||
|
||||
;************** add DL end entry on each DL *****************************
|
||||
|
||||
ldx #$0C
|
||||
dlendloop
|
||||
dex
|
||||
lda DLPOINTL,x
|
||||
sta dlpnt
|
||||
lda DLPOINTH,x
|
||||
sta dlpnt+1
|
||||
ldy dlend,x
|
||||
iny
|
||||
lda #$00
|
||||
sta (dlpnt),y
|
||||
txa
|
||||
bne dlendloop
|
||||
|
||||
vbloop
|
||||
lda MSTAT ;Wait for VBLANK to end
|
||||
and #$80
|
||||
bne vbloop
|
||||
|
||||
jmp mainloop ;Loop
|
||||
|
||||
redraw
|
||||
|
||||
|
||||
NMI
|
||||
RTI
|
||||
|
||||
IRQ
|
||||
RTI
|
||||
|
||||
|
||||
;Pointers to the DLs
|
||||
|
||||
DLPOINTH
|
||||
.byte $22,$22,$22,$22,$23,$23,$23,$23,$24,$24,$24,$24
|
||||
DLPOINTL
|
||||
.byte $00,$40,$80,$C0,$00,$40,$80,$C0,$00,$40,$80,$C0
|
||||
|
||||
|
||||
|
||||
|
||||
;************** Graphic Data *****************************
|
||||
;set org and fill character
|
||||
org $a000,0
|
||||
.byte %00111100
|
||||
org $a100
|
||||
.byte %00111100
|
||||
org $a200
|
||||
.byte %01000010
|
||||
org $a300
|
||||
.byte %01000010
|
||||
org $a400
|
||||
.byte %10011001
|
||||
org $a500
|
||||
.byte %10011001
|
||||
org $a600
|
||||
.byte %10100101
|
||||
org $a700
|
||||
.byte %10100101
|
||||
org $a800
|
||||
.byte %10000001
|
||||
org $a900
|
||||
.byte %10000001
|
||||
org $aA00
|
||||
.byte %10100101
|
||||
org $aB00
|
||||
.byte %10100101
|
||||
org $aC00
|
||||
.byte %01000010
|
||||
org $aD00
|
||||
.byte %01000010
|
||||
org $aE00
|
||||
.byte %00111100
|
||||
org $aF00
|
||||
.byte %00111100
|
||||
|
||||
|
||||
;************** Cart reset vector **************************
|
||||
|
||||
org $fff8
|
||||
.byte $FF ;Region verification
|
||||
.byte $87 ;ROM start $4000
|
||||
.word #NMI
|
||||
.word #START
|
||||
.word #IRQ
|
||||
|
||||
|
||||
|
37
src/audio.ts
37
src/audio.ts
@ -122,9 +122,18 @@ export var POKEYDeviceChannel = function() {
|
||||
var bit1 = new Uint8Array( [ 0,1 ] );
|
||||
var bit4 = new Uint8Array( [ 1,1,0,1,1,1,0,0,0,0,1,0,1,0,0 ] );
|
||||
var bit5 = new Uint8Array( [ 0,0,1,1,0,0,0,1,1,1,1,0,0,1,0,1,0,1,1,0,1,1,1,0,1,0,0,0,0,0,1 ] );
|
||||
var bit9 = new Uint8Array( [ 0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,0,1,0,1,0,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,0,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,1,0,0,0,0,1,1,0,1,1,0,0,0,1,0,0,0,1,1,1,1,0,1,0,1,1,0,1,0,1,0,0,0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,1,1,0,0,1,1,0,1,1,0,0,1,1,1,1,1,0,0,1,1,0,0,0,1,1,0,1,0,0,0,1,1,0,0,1,1,1,1,0,0,1,0,0,0,1,1,1,0,0,1,1,0,1,0,1,1,0,1,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,0,0,0,1,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,1,1,0,0,0,0,1,0,1,1,1,1,0,1,0,0,0,1,1,0,0,0,1,1,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,0,0,1,1,1,0,0,0,1,1,1,0,0,1,1,0,0,1,0,0,1,0,1,1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1,1,1,0,0,0,1,1,1,0,0,0,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,0,0,1,0,1,0,1,1,1,0,0,0,0,0,1,1,0,1,1,0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,1,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,0,0,1,1,0,1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,1,1,0,1,0,0,0,0,0,1,1,1,1,0,0,1,0,0,1,0,1,1,1,1,1,1,1,0,1,0,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,0,1,0,0,1,0,1,0,1,0,1,1,1,0,0,1,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,0 ] );
|
||||
var div31 = new Uint8Array( [ 1,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 ] );
|
||||
var bit17 = new Uint8Array(1<<17);
|
||||
var bit17_5 = new Uint8Array(1<<17);
|
||||
var bit5_4 = new Uint8Array(1<<17);
|
||||
var bit5_4 = new Uint8Array(1<<9);
|
||||
// TODO
|
||||
var bit6 = bit9;
|
||||
var bit15_4 = bit5_4;
|
||||
var bit5_2 = bit5_4;
|
||||
var bit5_6 = bit5_4;
|
||||
var bit31 = bit9;
|
||||
var bit93 = bit31;
|
||||
for (var i=0; i<bit17.length; i++) {
|
||||
bit17[i] = Math.random() > 0.5 ? 1 : 0;
|
||||
bit17_5[i] = bit17[i] & bit5[i % bit5.length];
|
||||
@ -134,6 +143,12 @@ export var POKEYDeviceChannel = function() {
|
||||
bit17_5, bit5, bit5_4, bit5,
|
||||
bit17, bit1, bit4, bit1
|
||||
];
|
||||
var tiawavetones = [
|
||||
bit1, bit4, bit15_4, bit5_4,
|
||||
bit1, bit1, bit31, bit5_2,
|
||||
bit9, bit5, bit31, bit1,
|
||||
bit6, bit6, bit93, bit5_6
|
||||
];
|
||||
|
||||
// registers
|
||||
var regs = new Uint8Array(16);
|
||||
@ -212,6 +227,24 @@ export var POKEYDeviceChannel = function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setTIARegister = function(addr, value) {
|
||||
switch (addr) {
|
||||
case 0x17:
|
||||
case 0x18:
|
||||
regs[(addr&1)*4] = value & 0x1f;
|
||||
dirty = true;
|
||||
break;
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
waveforms[(addr&1)*2] = tiawavetones[value & 0xf];
|
||||
break;
|
||||
case 0x19:
|
||||
case 0x1a:
|
||||
volume[(addr&1)*2] = value & 0xf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.generate = function (length) {
|
||||
if (dirty) {
|
||||
@ -236,7 +269,7 @@ export var POKEYDeviceChannel = function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
sample *= 128;
|
||||
sample *= 64;
|
||||
buffer[s] = sample;
|
||||
buffer[s+1] = sample;
|
||||
}
|
||||
|
@ -514,7 +514,7 @@ export abstract class BaseZ80Platform extends BaseDebugPlatform {
|
||||
return this._cpu;
|
||||
}
|
||||
|
||||
getProbe() { return this.probe; }
|
||||
getProbe() { return this.probe; } // TODO?
|
||||
getPC() { return this._cpu.getPC(); }
|
||||
getSP() { return this._cpu.getSP(); }
|
||||
|
||||
@ -691,6 +691,9 @@ export abstract class Base6809Platform extends BaseZ80Platform {
|
||||
return cpu;
|
||||
}
|
||||
|
||||
getPC() { return this._cpu.PC; }
|
||||
getSP() { return this._cpu.SP; }
|
||||
|
||||
runUntilReturn() {
|
||||
var depth = 1;
|
||||
this.runEval((c:CpuState) => {
|
||||
|
@ -575,12 +575,15 @@ export class ControllerPoller {
|
||||
}
|
||||
|
||||
|
||||
export function padBytes(data:Uint8Array|number[], len:number) : Uint8Array {
|
||||
export function padBytes(data:Uint8Array|number[], len:number, padstart?:boolean) : Uint8Array {
|
||||
if (data.length > len) {
|
||||
throw Error("Data too long, " + data.length + " > " + len);
|
||||
}
|
||||
var r = new RAM(len);
|
||||
r.mem.set(data);
|
||||
if (padstart)
|
||||
r.mem.set(data, len-data.length);
|
||||
else
|
||||
r.mem.set(data);
|
||||
return r.mem;
|
||||
}
|
||||
|
||||
|
@ -1,28 +1,269 @@
|
||||
"use strict";
|
||||
|
||||
import { Platform, Base6502Platform, BaseMAMEPlatform, getOpcodeMetadata_6502, getToolForFilename_6502 } from "../baseplatform";
|
||||
import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap, dumpRAM, getMousePos } from "../emu";
|
||||
import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap, dumpRAM, getMousePos, EmuHalt } from "../emu";
|
||||
import { hex, lzgmini, stringToByteArray, lpad, rpad, rgb2bgr } from "../util";
|
||||
import { MasterAudio, POKEYDeviceChannel, newPOKEYAudio } from "../audio";
|
||||
|
||||
declare var jt; // for 6502
|
||||
|
||||
// https://atarihq.com/danb/a7800.shtml
|
||||
// https://atarihq.com/danb/files/maria_r1.txt
|
||||
// https://sites.google.com/site/atari7800wiki/
|
||||
|
||||
var Atari7800_PRESETS = [
|
||||
{id:'sprites.dasm', name:'Sprites (ASM)'},
|
||||
];
|
||||
|
||||
const SWCHA = 0;
|
||||
const SWCHB = 1;
|
||||
const INPT4 = 2;
|
||||
const INPT5 = 3;
|
||||
|
||||
const Atari7800_KEYCODE_MAP = makeKeycodeMap([
|
||||
[Keys.VK_SPACE, 0, 0],
|
||||
[Keys.VK_ENTER, 0, 0],
|
||||
[Keys.A, INPT4, -0x80],
|
||||
//[Keys.B, 0, 1],
|
||||
//[Keys.SELECT, 0, 2],
|
||||
//[Keys.START, 0, 3],
|
||||
[Keys.UP, SWCHA, -0x10],
|
||||
[Keys.DOWN, SWCHA, -0x20],
|
||||
[Keys.LEFT, SWCHA, -0x40],
|
||||
[Keys.RIGHT, SWCHA, -0x80],
|
||||
|
||||
[Keys.P2_A, INPT5, -0x80],
|
||||
//[Keys.P2_B, 1, 1],
|
||||
//[Keys.P2_SELECT, 1, 2],
|
||||
//[Keys.P2_START, 1, 3],
|
||||
[Keys.P2_UP, SWCHA, -0x01],
|
||||
[Keys.P2_DOWN, SWCHA, -0x02],
|
||||
[Keys.P2_LEFT, SWCHA, -0x04],
|
||||
[Keys.P2_RIGHT, SWCHA, -0x08],
|
||||
]);
|
||||
|
||||
// http://www.ataripreservation.org/websites/freddy.offenga/megazine/ISSUE5-PALNTSC.html
|
||||
// http://7800.8bitdev.org/index.php/7800_Software_Guide#APPENDIX_4:_FRAME_TIMING
|
||||
const CLK = 3579545;
|
||||
const cpuFrequency = 1789772;
|
||||
const linesPerFrame = 262;
|
||||
const colorClocksPerLine = 228*2;
|
||||
const numVisibleLines = 258-16;
|
||||
const colorClocksPerLine = 454;
|
||||
const romLength = 0xc000;
|
||||
|
||||
// TIA chip
|
||||
|
||||
class TIA {
|
||||
regs = new Uint8Array(0x20);
|
||||
|
||||
reset() {
|
||||
// TODO
|
||||
}
|
||||
read(a : number) : number {
|
||||
return this.regs[a] | 0;
|
||||
}
|
||||
write(a : number, v : number) {
|
||||
this.regs[a] = v;
|
||||
}
|
||||
saveState() {
|
||||
return {
|
||||
regs: this.regs.slice(0)
|
||||
};
|
||||
}
|
||||
loadState(s) {
|
||||
for (let i=0; i<32; i++)
|
||||
this.write(i, s.regs[i]);
|
||||
}
|
||||
static stateToLongString(state) : string {
|
||||
let s = "";
|
||||
s += dumpRAM(state.regs, 0, 32);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
// MARIA chip
|
||||
|
||||
class MARIA {
|
||||
bus;
|
||||
cycles : number = 0;
|
||||
regs = new Uint8Array(0x20);
|
||||
offset : number = -1;
|
||||
dll : number = 0;
|
||||
dlstart : number = 0;
|
||||
dli : boolean = false;
|
||||
h16 : boolean = false;
|
||||
h8 : boolean = false;
|
||||
pixels = new Uint8Array(320);
|
||||
|
||||
reset() {
|
||||
// TODO
|
||||
}
|
||||
read(a : number) : number {
|
||||
return this.regs[a] | 0;
|
||||
}
|
||||
write(a : number, v : number) {
|
||||
this.regs[a] = v;
|
||||
//console.log(hex(a), '=', hex(v));
|
||||
}
|
||||
saveState() {
|
||||
return {
|
||||
regs: this.regs.slice(0),
|
||||
offset: this.offset,
|
||||
dll: this.dll,
|
||||
dlstart: this.dlstart,
|
||||
dli: this.dli,
|
||||
h16: this.h16,
|
||||
h8: this.h8,
|
||||
};
|
||||
}
|
||||
loadState(s) {
|
||||
for (let i=0; i<32; i++)
|
||||
this.write(i, s.regs[i]);
|
||||
this.offset = s.offset;
|
||||
this.dll = s.dll;
|
||||
this.dlstart = s.dlstart;
|
||||
this.dli = s.dli;
|
||||
this.h16 = s.h16;
|
||||
this.h8 = s.h8;
|
||||
}
|
||||
isDMAEnabled() {
|
||||
return (this.regs[0x1c] & 0x60) == 0x40;
|
||||
}
|
||||
getDLLStart() {
|
||||
return (this.regs[0x0c] << 8) + this.regs[0x10];
|
||||
}
|
||||
getCharBaseAddress() {
|
||||
return (this.regs[0x14] << 8) + this.offset;
|
||||
}
|
||||
setVBLANK(b : boolean) {
|
||||
if (b) {
|
||||
this.regs[0x08] |= 0x80;
|
||||
this.offset = -1;
|
||||
this.dll = this.getDLLStart(); // TODO?
|
||||
} else {
|
||||
this.regs[0x08] &= ~0x80;
|
||||
}
|
||||
}
|
||||
readDLLEntry(bus) {
|
||||
var x = bus.read(this.dll);
|
||||
this.offset = (x & 0xf);
|
||||
this.dli = (x & 0x80) != 0;
|
||||
this.h16 = (x & 0x40) != 0;
|
||||
this.h8 = (x & 0x20) != 0;
|
||||
this.dlstart = (bus.read(this.dll+1)<<8) + bus.read(this.dll+2);
|
||||
//console.log(hex(this.dll,4), this.offset, hex(this.dlstart,4));
|
||||
this.dll = (this.dll + 3) & 0xffff; // TODO: can only cross 1 page
|
||||
this.cycles += 8;
|
||||
}
|
||||
isHoley(a : number) : boolean {
|
||||
if (a & 0x8000) {
|
||||
if (this.h16 && (a & 0x1000)) return true;
|
||||
if (this.h8 && (a & 0x800)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
readDMA(a : number) : number {
|
||||
if (this.isHoley(a))
|
||||
return 0;
|
||||
else {
|
||||
this.cycles += 3;
|
||||
return this.bus.read(a);
|
||||
}
|
||||
}
|
||||
doDMA(bus) {
|
||||
this.bus = bus;
|
||||
this.cycles = 0;
|
||||
this.pixels.fill(this.regs[0x0]);
|
||||
if (this.isDMAEnabled()) {
|
||||
this.cycles += 16;
|
||||
// time for a new DLL entry?
|
||||
if (this.offset < 0) {
|
||||
this.readDLLEntry(bus);
|
||||
}
|
||||
// read the DL (only can span two pages)
|
||||
var dlhi = this.dlstart & 0xff00;
|
||||
var dlofs = this.dlstart & 0xff;
|
||||
do {
|
||||
// read DL entry
|
||||
var b0 = bus.read(dlhi + ((dlofs+0) & 0x1ff));
|
||||
var b1 = bus.read(dlhi + ((dlofs+1) & 0x1ff));
|
||||
if (b1 == 0) break; // end of DL
|
||||
var b2 = bus.read(dlhi + ((dlofs+2) & 0x1ff));
|
||||
var b3 = bus.read(dlhi + ((dlofs+3) & 0x1ff));
|
||||
var writemode = 0;
|
||||
var indirect = false;
|
||||
// extended header?
|
||||
if ((b1 & 31) == 0) {
|
||||
var pal = b3 >> 5;
|
||||
var width = 32 - (b3 & 31);
|
||||
var xpos = bus.read(dlhi + ((dlofs+4) & 0x1ff));
|
||||
writemode = b1 & 0x80;
|
||||
indirect = (b1 & 0x20) != 0;
|
||||
dlofs += 5;
|
||||
} else {
|
||||
// direct mode
|
||||
var xpos = b3;
|
||||
var pal = b1 >> 5;
|
||||
var width = 32 - (b1 & 31);
|
||||
dlofs += 4;
|
||||
}
|
||||
var gfxadr = b0 + (((b2 + (indirect?0:this.offset)) & 0xff) << 8);
|
||||
xpos *= 2;
|
||||
this.cycles += 4;
|
||||
// copy graphics data (direct)
|
||||
// TODO
|
||||
var readmode = (this.regs[0x1c] & 0x3) + (writemode?4:0);
|
||||
//if (this.offset == 0) console.log(hex(dla,4), hex(gfxadr,4), xpos, width, pal, readmode);
|
||||
for (var i=0; i<width; i++) {
|
||||
var data = this.readDMA(gfxadr + i);
|
||||
if (indirect) {
|
||||
// TODO: double bytes
|
||||
data = this.readDMA(((this.regs[0x14] + this.offset) << 8) + data);
|
||||
}
|
||||
switch (readmode) {
|
||||
case 0: // 160 A/B
|
||||
for (var j=0; j<4; j++) {
|
||||
var col = (data >> 6) & 3;
|
||||
if (col > 0) {
|
||||
this.pixels[xpos] = this.pixels[xpos+1] = this.regs[(pal<<2) + col];
|
||||
}
|
||||
data <<= 2;
|
||||
xpos = (xpos + 2) & 0x1ff;
|
||||
}
|
||||
break;
|
||||
case 2: // 320 B/D
|
||||
case 3: // 320 A/C
|
||||
for (var j=0; j<8; j++) {
|
||||
var col = data & 1;
|
||||
if (col > 0) {
|
||||
this.pixels[xpos] = this.regs[(pal<<2) + col];
|
||||
}
|
||||
data >>= 1;
|
||||
xpos = (xpos + 1) & 0x1ff;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (1);
|
||||
// decrement offset
|
||||
this.offset -= 1;
|
||||
}
|
||||
return this.cycles;
|
||||
}
|
||||
doInterrupt() : boolean {
|
||||
return this.dli && this.offset == 0;
|
||||
}
|
||||
static stateToLongString(state) : string {
|
||||
let s = "";
|
||||
s += dumpRAM(state.regs, 0, 32);
|
||||
s += "\n DLL: $" + hex((state.regs[0x0c] << 8) + state.regs[0x10],4) + " @ $" + hex(state.dll,4);
|
||||
s += "\n DL: $" + hex(state.dlstart,4);
|
||||
s += "\nOffset: " + state.offset;
|
||||
s += "\n DLI? " + state.dli;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
// Atari 7800
|
||||
|
||||
class Atari7800Platform extends Base6502Platform implements Platform {
|
||||
|
||||
mainElement : HTMLElement;
|
||||
@ -34,12 +275,16 @@ class Atari7800Platform extends Base6502Platform implements Platform {
|
||||
video;
|
||||
audio;
|
||||
timer : AnimationTimer;
|
||||
inputs = new Uint8Array(4);
|
||||
inputs = new Uint8Array(8);
|
||||
regs6532 = new Uint8Array(4);
|
||||
scanline : number = 0;
|
||||
tia : TIA = new TIA();
|
||||
maria : MARIA = new MARIA();
|
||||
|
||||
constructor(mainElement : HTMLElement) {
|
||||
super();
|
||||
this.mainElement = mainElement;
|
||||
this.inputs.fill(0xff);
|
||||
}
|
||||
|
||||
getPresets() {
|
||||
@ -53,27 +298,51 @@ class Atari7800Platform extends Base6502Platform implements Platform {
|
||||
// TODO: TIA access wastes a cycle
|
||||
this.bus = {
|
||||
read: newAddressDecoder([
|
||||
[0x0040, 0x00ff, 0xffff, (a) => { return this.ram[a]; }],
|
||||
[0x0140, 0x01ff, 0xffff, (a) => { return this.ram[a]; }],
|
||||
[0x1800, 0x27ff, 0xffff, (a) => { return this.ram[a - 0x1600]; }],
|
||||
[0x0008, 0x000b, 0x04, (a) => { return this.inputs[a]; }],
|
||||
[0x000c, 0x000d, 0x01, (a) => { return (this.inputs[INPT4 + a] & 0x80) ? 0x80 : 0x00; }],
|
||||
[0x0000, 0x001f, 0x1f, (a) => { return this.tia.read(a); }],
|
||||
[0x0020, 0x003f, 0x1f, (a) => { return this.maria.read(a); }],
|
||||
[0x0040, 0x00ff, 0xff, (a) => { return this.ram[a + 0x800]; }],
|
||||
[0x0100, 0x013f, 0xff, (a) => { return this.bus.read(a); }], // shadow
|
||||
[0x0140, 0x01ff, 0x1ff, (a) => { return this.ram[a + 0x800]; }],
|
||||
[0x0280, 0x02ff, 0x3, (a) => { return this.inputs[a]; }],
|
||||
[0x1800, 0x27ff, 0xffff, (a) => { return this.ram[a - 0x1800]; }],
|
||||
[0x2800, 0x3fff, 0x7ff, (a) => { return this.bus.read(a | 0x2000); }], // shadow
|
||||
[0x4000, 0xffff, 0xffff, (a) => { return this.rom ? this.rom[a - 0x4000] : 0; }],
|
||||
//[0xf000, 0xffff, 0xfff, (a) => { return this.bios ? this.bios[a] : 0; }],
|
||||
[0x0000, 0xffff, 0xffff, (a) => { throw new EmuHalt("Read @ " + hex(a,4)); }]
|
||||
]),
|
||||
write: newAddressDecoder([
|
||||
[0x0040, 0x00ff, 0xffff, (a,v) => { this.ram[a] = v; }],
|
||||
[0x0140, 0x01ff, 0xffff, (a,v) => { this.ram[a] = v; }],
|
||||
[0x1800, 0x27ff, 0xffff, (a,v) => { this.ram[a - 0x1600] = v; }],
|
||||
[0x0015, 0x001A, 0x1f, (a,v) => { this.audio.pokey1.setTIARegister(a, v); }],
|
||||
[0x0000, 0x001f, 0x1f, (a,v) => { this.tia.write(a,v); }],
|
||||
[0x0020, 0x003f, 0x1f, (a,v) => { this.maria.write(a,v); }],
|
||||
[0x0040, 0x00ff, 0xff, (a,v) => { this.ram[a + 0x800] = v; }],
|
||||
[0x0140, 0x01ff, 0x1ff, (a,v) => { this.ram[a + 0x800] = v; }],
|
||||
[0x0280, 0x02ff, 0x3, (a,v) => { this.regs6532[a] = v; /*TODO*/ }],
|
||||
[0x1800, 0x27ff, 0xffff, (a,v) => { this.ram[a - 0x1800] = v; }],
|
||||
[0x2800, 0x3fff, 0x7ff, (a,v) => { this.bus.write(a | 0x2000, v); }],
|
||||
[0x0000, 0xffff, 0xffff, (a,v) => { throw new EmuHalt("Write @ " + hex(a,4) + " " + hex(v,2)); }]
|
||||
]),
|
||||
};
|
||||
this.cpu.connectBus(this.bus);
|
||||
// create video/audio
|
||||
this.video = new RasterVideo(this.mainElement, 320, 192);
|
||||
this.video = new RasterVideo(this.mainElement, 320, numVisibleLines);
|
||||
this.audio = newPOKEYAudio(1);
|
||||
this.video.create();
|
||||
setKeyboardFromMap(this.video, this.inputs, Atari7800_KEYCODE_MAP, (o,key,code,flags) => {
|
||||
// TODO
|
||||
});
|
||||
this.timer = new AnimationTimer(60, this.nextFrame.bind(this));
|
||||
// setup mouse events
|
||||
var rasterPosBreakFn = (e) => {
|
||||
if (e.shiftKey) {
|
||||
var clickpos = getMousePos(e.target, e);
|
||||
this.runEval( (c) => {
|
||||
return (this.getRasterScanline() == (clickpos.y|0));
|
||||
});
|
||||
}
|
||||
};
|
||||
var jacanvas = $("#emulator").find("canvas");
|
||||
jacanvas.mousedown(rasterPosBreakFn);
|
||||
}
|
||||
|
||||
advance(novideo : boolean) {
|
||||
@ -81,39 +350,47 @@ class Atari7800Platform extends Base6502Platform implements Platform {
|
||||
var iofs = 0;
|
||||
var debugCond = this.getDebugCallback();
|
||||
var rgb;
|
||||
var freeClocks = 0;
|
||||
// load controls
|
||||
// TODO
|
||||
//gtia.regs[0x10] = inputs[0] ^ 1;
|
||||
var mariaClocks = 0;
|
||||
// visible lines
|
||||
for (var sl=0; sl<linesPerFrame; sl++) {
|
||||
freeClocks = 256; // TODO
|
||||
for (var i=0; i<colorClocksPerLine; i+=4) {
|
||||
this.scanline = sl;
|
||||
// iterate CPU with free clocks
|
||||
while (freeClocks > 0) {
|
||||
freeClocks--;
|
||||
if (debugCond && debugCond()) {
|
||||
debugCond = null;
|
||||
i = 999;
|
||||
sl = 999;
|
||||
break;
|
||||
}
|
||||
this.cpu.clockPulse();
|
||||
this.scanline = sl;
|
||||
this.maria.setVBLANK(sl >= numVisibleLines);
|
||||
mariaClocks += 454;
|
||||
// TODO: 7 cycles at start of line
|
||||
if (this.maria.isDMAEnabled()) {
|
||||
// do DMA for scanline
|
||||
mariaClocks -= this.maria.doDMA(this.bus);
|
||||
// copy line to frame buffer
|
||||
for (var i=0; i<320; i++) {
|
||||
idata[iofs++] = COLORS_RGBA[this.maria.pixels[i]];
|
||||
}
|
||||
// do interrupt?
|
||||
if (this.maria.doInterrupt()) {
|
||||
mariaClocks -= this.cpu.setNMIAndWait() * 4;
|
||||
}
|
||||
}
|
||||
// iterate CPU with free clocks
|
||||
while (mariaClocks > 0) {
|
||||
mariaClocks -= 4;
|
||||
if (debugCond && debugCond()) {
|
||||
debugCond = null;
|
||||
sl = 999;
|
||||
break;
|
||||
}
|
||||
this.cpu.clockPulse();
|
||||
}
|
||||
}
|
||||
// update video frame
|
||||
if (!novideo) {
|
||||
this.video.updateFrame();
|
||||
// set background/border color
|
||||
let bkcol = 0; //gtia.regs[COLBK];
|
||||
let bkcol = this.maria.regs[0x0];
|
||||
$(this.video.canvas).css('background-color', COLORS_WEB[bkcol]);
|
||||
}
|
||||
}
|
||||
|
||||
loadROM(title, data) {
|
||||
this.rom = padBytes(data, romLength);
|
||||
this.rom = padBytes(data, romLength, true);
|
||||
this.reset();
|
||||
}
|
||||
|
||||
@ -138,6 +415,8 @@ class Atari7800Platform extends Base6502Platform implements Platform {
|
||||
|
||||
reset() {
|
||||
this.cpu.reset();
|
||||
this.tia.reset();
|
||||
this.maria.reset();
|
||||
/*
|
||||
// execute until out of BIOS
|
||||
for (var i=0; i<20000; i++) {
|
||||
@ -157,13 +436,16 @@ class Atari7800Platform extends Base6502Platform implements Platform {
|
||||
this.cpu.loadState(state.c);
|
||||
this.fixPC(state.c);
|
||||
this.ram.set(state.b);
|
||||
this.tia.loadState(state.tia);
|
||||
this.maria.loadState(state.maria);
|
||||
this.loadControlsState(state);
|
||||
}
|
||||
|
||||
saveState() {
|
||||
return {
|
||||
c:this.getCPUState(),
|
||||
b:this.ram.slice(0),
|
||||
tia:this.tia.saveState(),
|
||||
maria:this.maria.saveState(),
|
||||
in:this.inputs.slice(0)
|
||||
};
|
||||
}
|
||||
@ -186,18 +468,16 @@ class Atari7800Platform extends Base6502Platform implements Platform {
|
||||
return this.scanline;
|
||||
}
|
||||
|
||||
/*
|
||||
getDebugCategories() {
|
||||
return super.getDebugCategories().concat(['ANTIC','GTIA']);
|
||||
return super.getDebugCategories().concat(['TIA','MARIA']);
|
||||
}
|
||||
getDebugInfo(category, state) {
|
||||
switch (category) {
|
||||
case 'ANTIC': return ANTIC.stateToLongString(state.antic);
|
||||
case 'GTIA': return GTIA.stateToLongString(state.gtia);
|
||||
case 'TIA': return TIA.stateToLongString(state.tia);
|
||||
case 'MARIA': return MARIA.stateToLongString(state.maria) + "\nScanline: " + this.scanline;
|
||||
default: return super.getDebugInfo(category, state);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -23,6 +23,7 @@ var WilliamsPlatform = function(mainElement, proto) {
|
||||
var portsel = 0;
|
||||
var banksel = 0;
|
||||
var watchdog_counter;
|
||||
var watchdog_enabled = false;
|
||||
var pia6821 = new RAM(8).mem;
|
||||
var blitregs = new RAM(8).mem;
|
||||
|
||||
@ -334,7 +335,7 @@ var WilliamsPlatform = function(mainElement, proto) {
|
||||
drawDisplayByte(i, ram.mem[i]);
|
||||
screenNeedsRefresh = false;
|
||||
}
|
||||
if (watchdog_counter-- <= 0) {
|
||||
if (watchdog_enabled && watchdog_counter-- <= 0) {
|
||||
console.log("WATCHDOG FIRED, PC =", cpu.getPC().toString(16)); // TODO: alert on video
|
||||
// TODO: this.breakpointHit(cpu.T());
|
||||
this.reset();
|
||||
|
@ -274,6 +274,15 @@ var PLATFORM_PARAMS = {
|
||||
define: '__ATARI7800__',
|
||||
cfgfile: 'atari7800.cfg',
|
||||
libargs: ['atari7800.lib'],
|
||||
extra_segments:[
|
||||
{name:'TIA',start:0x00,size:0x20,type:'io'},
|
||||
{name:'MARIA',start:0x20,size:0x20,type:'io'},
|
||||
{name:'RAM (6166 Block 0)',start:0x40,size:0xc0,type:'ram'},
|
||||
{name:'RAM (6166 Block 1)',start:0x140,size:0xc0,type:'ram'},
|
||||
{name:'PIA',start:0x280,size:0x18,type:'io'},
|
||||
{name:'RAM',start:0x1800,size:0x1000,type:'ram'}, // TODO: shadow ram
|
||||
{name:'Cartridge ROM',start:0x4000,size:0xc000,type:'rom'},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -15,6 +15,7 @@ dom.window.Audio = null;
|
||||
global.Image = function() { }
|
||||
global['$'] = require("jquery/jquery-2.2.3.min.js");
|
||||
includeInThisContext('src/cpu/z80.js');
|
||||
includeInThisContext('src/cpu/6809.js');
|
||||
global['buildZ80'] = global.window.buildZ80;
|
||||
includeInThisContext("javatari.js/release/javatari/javatari.js");
|
||||
Javatari.AUTO_START = false;
|
||||
@ -232,7 +233,14 @@ describe('Platform Replay', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Should run williams', () => {
|
||||
it('Should run williams 6809', () => {
|
||||
var platform = testPlatform('williams', 'vidfill.asm.rom', 72, (platform, frameno) => {
|
||||
if (frameno == 62) {
|
||||
keycallback(Keys.VK_LEFT.c, Keys.VK_LEFT.c, 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
it('Should run williams-z80', () => {
|
||||
var platform = testPlatform('williams-z80', 'game1.c.rom', 72, (platform, frameno) => {
|
||||
if (frameno == 62) {
|
||||
keycallback(Keys.VK_LEFT.c, Keys.VK_LEFT.c, 1);
|
||||
|
BIN
test/roms/williams/vidfill.asm.rom
Normal file
BIN
test/roms/williams/vidfill.asm.rom
Normal file
Binary file not shown.
1
tools/bin2arr.py
Normal file → Executable file
1
tools/bin2arr.py
Normal file → Executable file
@ -1,3 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user