williams: added test for 6809; fiddled with atari7800

This commit is contained in:
Steven Hugg 2019-08-11 10:23:56 -04:00
parent 4dfab17e7b
commit 4d5c6b9063
11 changed files with 830 additions and 486 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
}
*/
}
///

View File

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

View File

@ -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'},
],
},
};

View File

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

Binary file not shown.

1
tools/bin2arr.py Normal file → Executable file
View File

@ -1,3 +1,4 @@
#!/usr/bin/python
import sys