mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-06-03 04:29:33 +00:00
changes to multisprite; moved inspect to vcs for now; local book links; z80 disasm
This commit is contained in:
parent
61d7860e12
commit
9d70c0fb9c
|
@ -156,7 +156,7 @@ We're always adding new things here, so subscribe to our mailing list for update
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<a target="_blank" href="https://www.amazon.com/gp/product/1541021304/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1541021304&linkCode=as2&tag=pzp-20&linkId=c149f6365c0a676065eb6d7c5f8dd6ae" onclick="ga('send', 'event', 'books', 'click', 'vcs');">
|
<a target="_blank" href="https://www.amazon.com/gp/product/1541021304/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1541021304&linkCode=as2&tag=pzp-20&linkId=c149f6365c0a676065eb6d7c5f8dd6ae" onclick="ga('send', 'event', 'books', 'click', 'vcs');">
|
||||||
<img class="img-responsive" border="0" src="//ws-na.amazon-adsystem.com/widgets/q?_encoding=UTF8&MarketPlace=US&ASIN=1541021304&ServiceVersion=20070822&ID=AsinImage&WS=1&Format=_SL250_&tag=pzp-20" ></a>
|
<img class="img-responsive" border="0" src="./images/book_a2600_med.jpg" ></a>
|
||||||
<img src="//ir-na.amazon-adsystem.com/e/ir?t=pzp-20&l=am2&o=1&a=1541021304" />
|
<img src="//ir-na.amazon-adsystem.com/e/ir?t=pzp-20&l=am2&o=1&a=1541021304" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
|
@ -167,7 +167,7 @@ We're always adding new things here, so subscribe to our mailing list for update
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<a target="_blank" href="https://www.amazon.com/gp/product/1545484759/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1545484759&linkCode=as2&tag=pzp-20&linkId=2f3c42111bffe3466830939fff4053fc" onclick="ga('send', 'event', 'books', 'click', 'arcade');">
|
<a target="_blank" href="https://www.amazon.com/gp/product/1545484759/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1545484759&linkCode=as2&tag=pzp-20&linkId=2f3c42111bffe3466830939fff4053fc" onclick="ga('send', 'event', 'books', 'click', 'arcade');">
|
||||||
<img class="img-responsive" border="0" src="//ws-na.amazon-adsystem.com/widgets/q?_encoding=UTF8&MarketPlace=US&ASIN=1545484759&ServiceVersion=20070822&ID=AsinImage&WS=1&Format=_SL250_&tag=pzp-20" ></a>
|
<img class="img-responsive" border="0" src="./images/book_arcade_med.jpg" ></a>
|
||||||
<img src="//ir-na.amazon-adsystem.com/e/ir?t=pzp-20&l=am2&o=1&a=1545484759" />
|
<img src="//ir-na.amazon-adsystem.com/e/ir?t=pzp-20&l=am2&o=1&a=1545484759" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
|
|
|
@ -56,8 +56,9 @@ TODO:
|
||||||
- VCS skips step on lsr/lsr after run to line
|
- VCS skips step on lsr/lsr after run to line
|
||||||
- update window list after building 2nd time?
|
- update window list after building 2nd time?
|
||||||
- stop debugging where mouse clicked
|
- stop debugging where mouse clicked
|
||||||
|
- bring back the profiler!
|
||||||
|
- vcs disasm is broken
|
||||||
|
|
||||||
FYI: Image links for the books on http://8bitworkshop.com/ are broken
|
|
||||||
On the website the additional grey spacing next to the program line numbers is not dynamically resized when the web browser window size is changed. Intentional?
|
On the website the additional grey spacing next to the program line numbers is not dynamically resized when the web browser window size is changed. Intentional?
|
||||||
|
|
||||||
|
|
||||||
|
|
BIN
images/book_a2600_med.jpg
Normal file
BIN
images/book_a2600_med.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
images/book_arcade_med.jpg
Normal file
BIN
images/book_arcade_med.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
|
@ -309,6 +309,7 @@ function require(modname) {
|
||||||
<script src="gen/analysis.js"></script>
|
<script src="gen/analysis.js"></script>
|
||||||
<script src="gen/audio.js"></script>
|
<script src="gen/audio.js"></script>
|
||||||
<script src="gen/cpu/disasm6502.js"></script>
|
<script src="gen/cpu/disasm6502.js"></script>
|
||||||
|
<script src="gen/cpu/disasmz80.js"></script>
|
||||||
<script src="gen/workertypes.js"></script>
|
<script src="gen/workertypes.js"></script>
|
||||||
<script src="gen/project.js"></script>
|
<script src="gen/project.js"></script>
|
||||||
<script src="gen/windows.js"></script>
|
<script src="gen/windows.js"></script>
|
||||||
|
|
|
@ -17,35 +17,6 @@ THREE_COPIES equ %011 ; for NUSIZ registers
|
||||||
|
|
||||||
seg Code
|
seg Code
|
||||||
|
|
||||||
; setup 6-digit score
|
|
||||||
Digit6Setup: subroutine
|
|
||||||
lda #$18
|
|
||||||
sta COLUP0
|
|
||||||
lda #$28
|
|
||||||
sta COLUP1
|
|
||||||
lda #THREE_COPIES
|
|
||||||
sta NUSIZ0
|
|
||||||
sta NUSIZ1
|
|
||||||
; set horizontal position of player objects
|
|
||||||
sta WSYNC
|
|
||||||
SLEEP 26
|
|
||||||
sta RESP0
|
|
||||||
sta RESP1
|
|
||||||
lda #$10
|
|
||||||
sta HMP1
|
|
||||||
sta WSYNC
|
|
||||||
sta HMOVE
|
|
||||||
sta HMCLR
|
|
||||||
lda #0
|
|
||||||
sta REFP0
|
|
||||||
sta REFP1
|
|
||||||
sta GRP0
|
|
||||||
sta GRP1
|
|
||||||
lda #1
|
|
||||||
sta VDELP0
|
|
||||||
sta VDELP1
|
|
||||||
rts
|
|
||||||
|
|
||||||
; Adds value to 6-BCD-digit score.
|
; Adds value to 6-BCD-digit score.
|
||||||
; A = 1st BCD digit
|
; A = 1st BCD digit
|
||||||
; X = 2nd BCD digit
|
; X = 2nd BCD digit
|
||||||
|
@ -97,13 +68,40 @@ GetDigitPtrs: subroutine
|
||||||
|
|
||||||
; Display the resulting 48x8 bitmap
|
; Display the resulting 48x8 bitmap
|
||||||
; using the Digit0-5 pointers.
|
; using the Digit0-5 pointers.
|
||||||
|
; A = color of scoreboard
|
||||||
DrawDigits: subroutine
|
DrawDigits: subroutine
|
||||||
.temp equ Temp1
|
.temp equ Temp1
|
||||||
.count equ Temp2
|
.count equ Temp2
|
||||||
sta WSYNC
|
; clear player bitmaps first
|
||||||
SLEEP 40 ; start near end of scanline
|
jsr ClearGRP
|
||||||
lda #7
|
; set colors
|
||||||
sta .count
|
sta COLUP0
|
||||||
|
sta COLUP1
|
||||||
|
; set horizontal position of player objects
|
||||||
|
sta WSYNC
|
||||||
|
; instead of SLEEP 26...
|
||||||
|
lda #THREE_COPIES
|
||||||
|
sta NUSIZ0
|
||||||
|
sta NUSIZ1
|
||||||
|
lda #1
|
||||||
|
sta VDELP0
|
||||||
|
sta VDELP1
|
||||||
|
lda #$10
|
||||||
|
sta HMP1
|
||||||
|
stx HMP0 ; x = 0
|
||||||
|
nop
|
||||||
|
; set player positions (26 cycles later)
|
||||||
|
stx RESP0
|
||||||
|
stx RESP1
|
||||||
|
stx REFP0
|
||||||
|
stx REFP1
|
||||||
|
; apply fine adjustment
|
||||||
|
sta WSYNC
|
||||||
|
sta HMOVE
|
||||||
|
sta HMCLR
|
||||||
|
lda #8
|
||||||
|
sta .count ; 8 scanlines
|
||||||
|
jsr ClearGRP ; just killing some time...
|
||||||
.bigloop
|
.bigloop
|
||||||
ldy .count ; counts backwards
|
ldy .count ; counts backwards
|
||||||
lda (Digit0),y ; load B0 (1st sprite byte)
|
lda (Digit0),y ; load B0 (1st sprite byte)
|
||||||
|
@ -119,18 +117,19 @@ DrawDigits: subroutine
|
||||||
tax ; -> X
|
tax ; -> X
|
||||||
lda (Digit3),y ; load B3 -> A
|
lda (Digit3),y ; load B3 -> A
|
||||||
ldy .temp ; load B5 -> Y
|
ldy .temp ; load B5 -> Y
|
||||||
|
.storegrp
|
||||||
sta GRP1 ; B3 -> [GRP1]; B2 -> GRP0
|
sta GRP1 ; B3 -> [GRP1]; B2 -> GRP0
|
||||||
stx GRP0 ; B4 -> [GRP0]; B3 -> GRP1
|
stx GRP0 ; B4 -> [GRP0]; B3 -> GRP1
|
||||||
sty GRP1 ; B5 -> [GRP1]; B4 -> GRP0
|
sty GRP1 ; B5 -> [GRP1]; B4 -> GRP0
|
||||||
sta GRP0 ; ?? -> [GRP0]; B5 -> GRP1
|
sta GRP0 ; ?? -> [GRP0]; B5 -> GRP1
|
||||||
dec .count ; go to next line
|
dec .count ; go to next line
|
||||||
bpl .bigloop ; repeat until < 0
|
bpl .bigloop ; repeat until < 0
|
||||||
|
ClearGRP
|
||||||
lda #0 ; clear the sprite registers
|
ldx #0 ; empty out player bitmaps
|
||||||
sta GRP0
|
stx GRP0
|
||||||
sta GRP1
|
stx GRP1
|
||||||
sta GRP0
|
stx GRP0
|
||||||
sta GRP1
|
stx GRP1
|
||||||
rts
|
rts
|
||||||
|
|
||||||
; Font table for digits 0-9 (8x8 pixels)
|
; Font table for digits 0-9 (8x8 pixels)
|
||||||
|
@ -141,4 +140,4 @@ Digit6Font:
|
||||||
hex 0006067f661e0e06003c6606067c607e
|
hex 0006067f661e0e06003c6606067c607e
|
||||||
hex 003c66667c60663c00181818180c667e
|
hex 003c66667c60663c00181818180c667e
|
||||||
hex 003c66663c66663c003c66063e66663c
|
hex 003c66663c66663c003c66063e66663c
|
||||||
|
hex 00 ; so top of 9 is clean
|
||||||
|
|
|
@ -40,7 +40,7 @@ InitLoop
|
||||||
sta YPos0,x
|
sta YPos0,x
|
||||||
sta Flags0,x
|
sta Flags0,x
|
||||||
clc
|
clc
|
||||||
adc #13
|
adc #23
|
||||||
iny
|
iny
|
||||||
iny
|
iny
|
||||||
iny
|
iny
|
||||||
|
@ -68,6 +68,9 @@ InitLoop
|
||||||
sta PF1Ptr+1
|
sta PF1Ptr+1
|
||||||
lda #>Start+1
|
lda #>Start+1
|
||||||
sta PF2Ptr+1
|
sta PF2Ptr+1
|
||||||
|
lda YPos0+1
|
||||||
|
adc #9
|
||||||
|
sta YPos0+1
|
||||||
|
|
||||||
; Next frame loop
|
; Next frame loop
|
||||||
NextFrame
|
NextFrame
|
||||||
|
@ -76,12 +79,12 @@ NextFrame
|
||||||
; Do joystick movement
|
; Do joystick movement
|
||||||
ldy #1
|
ldy #1
|
||||||
jsr MoveJoystick
|
jsr MoveJoystick
|
||||||
jsr Digit6Setup
|
|
||||||
jsr GetDigitPtrs
|
jsr GetDigitPtrs
|
||||||
jsr MSpritePre
|
jsr MSpritePre
|
||||||
TIMER_WAIT
|
TIMER_WAIT
|
||||||
; end of VBLANK
|
; end of VBLANK
|
||||||
|
|
||||||
|
; Needed for single-line kernel
|
||||||
TIMER_TABLE_SETUP
|
TIMER_TABLE_SETUP
|
||||||
; Scoreboard
|
; Scoreboard
|
||||||
jsr DrawDigits
|
jsr DrawDigits
|
||||||
|
@ -90,7 +93,6 @@ NextFrame
|
||||||
sta COLUBK
|
sta COLUBK
|
||||||
lda #22
|
lda #22
|
||||||
jsr MSpriteDraw2
|
jsr MSpriteDraw2
|
||||||
|
|
||||||
; Overscan
|
; Overscan
|
||||||
TIMER_SETUP 28
|
TIMER_SETUP 28
|
||||||
; Clear all colors to black before overscan
|
; Clear all colors to black before overscan
|
||||||
|
@ -99,6 +101,11 @@ NextFrame
|
||||||
stx COLUP0
|
stx COLUP0
|
||||||
stx COLUP1
|
stx COLUP1
|
||||||
stx COLUPF
|
stx COLUPF
|
||||||
|
; add score
|
||||||
|
ldy #0
|
||||||
|
ldx #0
|
||||||
|
lda #1
|
||||||
|
jsr AddScore
|
||||||
; 30-2 lines of overscan
|
; 30-2 lines of overscan
|
||||||
TIMER_WAIT
|
TIMER_WAIT
|
||||||
; Go to next frame
|
; Go to next frame
|
||||||
|
|
|
@ -45,16 +45,20 @@
|
||||||
; MSpriteDraw1 - Single-line sprites, no playfield.
|
; MSpriteDraw1 - Single-line sprites, no playfield.
|
||||||
; This kernel requires TIMER_TABLE_SETUP at the 0th
|
; This kernel requires TIMER_TABLE_SETUP at the 0th
|
||||||
; scanline, as it uses the timer to figure out the
|
; scanline, as it uses the timer to figure out the
|
||||||
; current scanline.
|
; current scanline. No vertical clipping is performed.
|
||||||
|
; In fact, if sprites go past the bottom, it will
|
||||||
|
; mess up the vertical sync.
|
||||||
|
|
||||||
; MSpriteDraw2 - Double-line sprites with playfield.
|
; MSpriteDraw2 - Double-line sprites with playfield.
|
||||||
; The playfield is updated and the sprites are positioned
|
; The playfield is updated and the sprites are positioned
|
||||||
; in 8-scanline segments.
|
; in 8-scanline segments.
|
||||||
; This kernel uses the timer internally, but does not
|
; This kernel uses the timer internally, but does not
|
||||||
; use the timer table or TIMER_TABLE_SETUP.
|
; use the timer table or TIMER_TABLE_SETUP.
|
||||||
|
; Sprites are clipped on the bottom edge, but disappear
|
||||||
|
; off the top edge.
|
||||||
|
|
||||||
; Your program must call MSpriteInit when it starts,
|
; Your program must call MSpriteInit when it starts,
|
||||||
; and MSpritePre between every frame.
|
; and MSpriteFrame between every frame.
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
@ -119,7 +123,7 @@ MSpriteInit subroutine
|
||||||
rts
|
rts
|
||||||
|
|
||||||
; call between frames
|
; call between frames
|
||||||
MSpritePre subroutine
|
MSpriteFrame subroutine
|
||||||
; Do one iteration of bubble sort on sprite indices
|
; Do one iteration of bubble sort on sprite indices
|
||||||
ldx #NSprites-2
|
ldx #NSprites-2
|
||||||
.SortLoop
|
.SortLoop
|
||||||
|
@ -127,20 +131,18 @@ MSpritePre subroutine
|
||||||
dex
|
dex
|
||||||
bpl .SortLoop ; loop until <= 0
|
bpl .SortLoop ; loop until <= 0
|
||||||
; Reset scanline counter and sprite objects
|
; Reset scanline counter and sprite objects
|
||||||
ldx #0
|
jsr ResetCounters
|
||||||
stx CurIndex
|
stx CurIndex
|
||||||
stx SIndx0
|
|
||||||
stx SIndx1
|
|
||||||
stx SSize0
|
|
||||||
stx SSize1
|
|
||||||
rts
|
rts
|
||||||
|
|
||||||
; single-line kernel routine
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
; SINGLE-LINE KERNEL
|
||||||
|
|
||||||
MSpriteDraw1 subroutine
|
MSpriteDraw1 subroutine
|
||||||
.NextFindSprite
|
.NextFindSprite
|
||||||
; Try to schedule sprites to both players
|
; Try to schedule sprites to both players
|
||||||
jsr FindAnotherSprite
|
jsr FindAnotherSprite
|
||||||
jsr FindAnotherSprite
|
|
||||||
; Apply fine offsets
|
; Apply fine offsets
|
||||||
sta WSYNC ; start next scanline
|
sta WSYNC ; start next scanline
|
||||||
sta HMOVE ; apply the previous fine position(s)
|
sta HMOVE ; apply the previous fine position(s)
|
||||||
|
@ -157,6 +159,106 @@ MSpriteDraw1 subroutine
|
||||||
lda #191
|
lda #191
|
||||||
jmp WaitForScanline
|
jmp WaitForScanline
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
; DOUBLE-LINE KERNEL WITH BACKGROUND
|
||||||
|
|
||||||
|
MSpritePrefill2 subroutine
|
||||||
|
lda #0
|
||||||
|
sta Scanline
|
||||||
|
jsr FindAnotherSprite2
|
||||||
|
jsr FindAnotherSprite2
|
||||||
|
sta WSYNC
|
||||||
|
sta HMOVE ; apply the previous fine position(s)
|
||||||
|
sta HMCLR ; clear motion registers
|
||||||
|
rts
|
||||||
|
|
||||||
|
MSpriteDraw2 subroutine
|
||||||
|
sta WSYNC
|
||||||
|
sta PFIndex ; 24 * 4 scanlines = 96 2xlines
|
||||||
|
lda #0
|
||||||
|
sta PFCount
|
||||||
|
sta VDELP1
|
||||||
|
lda #1
|
||||||
|
sta VDELP0 ; updates to GRP0 will be delayed
|
||||||
|
jmp .NewSprites
|
||||||
|
.Draw8Lines
|
||||||
|
; Phase 0: Fetch PF0 byte
|
||||||
|
jsr DrawSprites2
|
||||||
|
ldy PFIndex
|
||||||
|
lda (PF0Ptr),y ; load PF0
|
||||||
|
sta tmpPF0
|
||||||
|
; Phase 1: Fetch PF1 byte
|
||||||
|
jsr DrawSprites2
|
||||||
|
ldy PFIndex
|
||||||
|
lda (PF1Ptr),y ; load PF1
|
||||||
|
sta tmpPF1
|
||||||
|
; Phase 2: Fetch PF2 byte
|
||||||
|
jsr DrawSprites2
|
||||||
|
ldy PFIndex
|
||||||
|
lda (PF2Ptr),y ; load PF2
|
||||||
|
sty PFIndex
|
||||||
|
sta tmpPF2
|
||||||
|
; Phase 3: Write PF0/PF1/PF2 registers
|
||||||
|
jsr DrawSprites2
|
||||||
|
lda tmpPF0
|
||||||
|
sta PF0
|
||||||
|
lda tmpPF1
|
||||||
|
sta PF1
|
||||||
|
lda tmpPF2
|
||||||
|
sta PF2
|
||||||
|
; Go to next scanline, unless playfield is done
|
||||||
|
; or unless this segment is done
|
||||||
|
dec PFIndex
|
||||||
|
bmi .NoMoreLines ; playfield done
|
||||||
|
dec PFCount
|
||||||
|
bpl .Draw8Lines ; keep drawing
|
||||||
|
; done drawing, reset player counters
|
||||||
|
jsr ResetCounters
|
||||||
|
.NewSprites
|
||||||
|
lda PFIndex
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
eor #$7f
|
||||||
|
sbc #34
|
||||||
|
sta Scanline ; Scanlines = 127 - PFIndex*4
|
||||||
|
; Set up 0-2 player objects taking up to 8 scanlines
|
||||||
|
TIMER_SETUP 7
|
||||||
|
jsr FindAnotherSprite2
|
||||||
|
jsr CalcSpriteEnd
|
||||||
|
; Update playfield
|
||||||
|
ldy PFIndex
|
||||||
|
lda (PF0Ptr),y ; load PF0 -> X
|
||||||
|
tax
|
||||||
|
lda (PF1Ptr),y ; load PF1 -> tmp
|
||||||
|
sta tmpPF1
|
||||||
|
lda (PF2Ptr),y ; load PF2 -> Y
|
||||||
|
tay
|
||||||
|
; Apply fine offsets
|
||||||
|
TIMER_WAIT ; wait for 8th scanlines and WSYNC
|
||||||
|
sta HMOVE ; apply the previous fine position(s)
|
||||||
|
sta HMCLR ; clear motion registers
|
||||||
|
; Store playfield registers
|
||||||
|
stx PF0
|
||||||
|
lda tmpPF1
|
||||||
|
sta PF1
|
||||||
|
sty PF2
|
||||||
|
dec PFIndex ; no more playfield?
|
||||||
|
bmi .NoMoreLines
|
||||||
|
lda PFCount
|
||||||
|
bne .Draw8Lines
|
||||||
|
sta WSYNC ; one more line
|
||||||
|
beq .NewSprites
|
||||||
|
.NoMoreLines
|
||||||
|
rts
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
; SPRITE DRAWING ROUTINES
|
||||||
|
; used by kernels
|
||||||
|
; need to set SIndx0/1, SSize0/1, PData0/1, PColr0/1
|
||||||
|
; all players must already be setup
|
||||||
|
|
||||||
; called by single-line kernel
|
; called by single-line kernel
|
||||||
DrawSprites1 subroutine
|
DrawSprites1 subroutine
|
||||||
; Wait for next precise scanline
|
; Wait for next precise scanline
|
||||||
|
@ -166,6 +268,7 @@ DrawSprites1 subroutine
|
||||||
lda Timer2Scanline,y ; lookup scanline #
|
lda Timer2Scanline,y ; lookup scanline #
|
||||||
beq .AnotherScanline ; not if zero!
|
beq .AnotherScanline ; not if zero!
|
||||||
sta Scanline ; save it
|
sta Scanline ; save it
|
||||||
|
DrawSprites1a
|
||||||
; Calculate # of lines to draw for each sprite
|
; Calculate # of lines to draw for each sprite
|
||||||
; Sprite Y - current scanline + sprite height
|
; Sprite Y - current scanline + sprite height
|
||||||
lda SIndx0
|
lda SIndx0
|
||||||
|
@ -193,6 +296,7 @@ DrawSprites1 subroutine
|
||||||
tax ; X = # of lines left to draw
|
tax ; X = # of lines left to draw
|
||||||
beq .NoSprites ; X = 0? we're done
|
beq .NoSprites ; X = 0? we're done
|
||||||
sta WSYNC ; next scanline
|
sta WSYNC ; next scanline
|
||||||
|
DrawSprites1b
|
||||||
.DrawNextScanline
|
.DrawNextScanline
|
||||||
; Make sure player 0 index is within bounds
|
; Make sure player 0 index is within bounds
|
||||||
ldy SIndx0
|
ldy SIndx0
|
||||||
|
@ -227,10 +331,7 @@ DrawSprites1 subroutine
|
||||||
dex
|
dex
|
||||||
bne .DrawNextScanline
|
bne .DrawNextScanline
|
||||||
; Free up both player objects by zeroing them out
|
; Free up both player objects by zeroing them out
|
||||||
stx SIndx0
|
jsr ResetCounters
|
||||||
stx SIndx1
|
|
||||||
stx SSize0
|
|
||||||
stx SSize1
|
|
||||||
sta WSYNC
|
sta WSYNC
|
||||||
stx GRP0
|
stx GRP0
|
||||||
stx GRP1
|
stx GRP1
|
||||||
|
@ -245,86 +346,41 @@ DrawSprites1 subroutine
|
||||||
sta COLUP0
|
sta COLUP0
|
||||||
beq .DrawSprite1 ; always taken due to lda #0
|
beq .DrawSprite1 ; always taken due to lda #0
|
||||||
|
|
||||||
MSpriteDraw2 subroutine
|
; called by 2-line kernel
|
||||||
sta WSYNC
|
DrawSprites2 subroutine
|
||||||
sta PFIndex ; 24 * 4 scanlines = 96 2xlines
|
; Fetch sprite 0 values
|
||||||
lda #0
|
lda SSize0 ; height in 2xlines
|
||||||
sta PFCount
|
sec
|
||||||
sta VDELP1
|
isb SIndx0 ; INC yp0, then SBC yp0
|
||||||
lda #1
|
bcs DoDraw0 ; inside bounds?
|
||||||
sta VDELP0 ; updates to GRP0 will be delayed
|
lda #0 ; no, load the padding offset (0)
|
||||||
.KernelLoop
|
DoDraw0
|
||||||
dec PFCount
|
tay ; -> Y
|
||||||
bmi .NewSprites
|
lda (PColr0),y ; color for both lines
|
||||||
.Draw8Lines
|
sta Colp0 ; -> colp0
|
||||||
; Phase 0: Fetch PF0 byte
|
lda (PData0),y ; bitmap for first line
|
||||||
jsr DrawSprites2
|
sta GRP0 ; -> [GRP0] (delayed due to VDEL)
|
||||||
ldy PFIndex
|
; Fetch sprite 1 values
|
||||||
lda (PF0Ptr),y ; load PF0
|
lda SSize1 ; height in 2xlines
|
||||||
sta tmpPF0
|
sec
|
||||||
; Phase 1: Fetch PF1 byte
|
isb SIndx1 ; INC yp0, then SBC yp0
|
||||||
jsr DrawSprites2
|
bcs DoDraw1 ; inside bounds?
|
||||||
ldy PFIndex
|
lda #0 ; no, load the padding offset (0)
|
||||||
lda (PF1Ptr),y ; load PF1
|
DoDraw1
|
||||||
sta tmpPF1
|
tay ; -> Y
|
||||||
; Phase 2: Fetch PF2 byte
|
lda (PColr1),y ; color for both lines
|
||||||
jsr DrawSprites2
|
|
||||||
ldy PFIndex
|
|
||||||
lda (PF2Ptr),y ; load PF2
|
|
||||||
sty PFIndex
|
|
||||||
sta tmpPF2
|
|
||||||
; Phase 3: Write PF0/PF1/PF2 registers
|
|
||||||
jsr DrawSprites2
|
|
||||||
lda tmpPF0
|
|
||||||
sta PF0
|
|
||||||
lda tmpPF1
|
|
||||||
sta PF1
|
|
||||||
lda tmpPF2
|
|
||||||
sta PF2
|
|
||||||
; Go to next scanline, unless playfield is done
|
|
||||||
dec PFIndex
|
|
||||||
bpl .KernelLoop
|
|
||||||
.NoMoreLines
|
|
||||||
rts
|
|
||||||
.NewSprites
|
|
||||||
; lda PFIndex
|
|
||||||
; sta COLUBK
|
|
||||||
lda PFIndex
|
|
||||||
asl
|
|
||||||
asl
|
|
||||||
eor #$7f
|
|
||||||
sbc #34
|
|
||||||
sta Scanline ; Scanlines = 127 - PFIndex*4
|
|
||||||
; Set up 0-2 player objects taking up to 8 scanlines
|
|
||||||
TIMER_SETUP 8
|
|
||||||
ldx #0
|
|
||||||
stx SSize0
|
|
||||||
stx SSize1
|
|
||||||
stx SIndx0
|
|
||||||
stx SIndx1
|
|
||||||
jsr FindAnotherSprite2
|
|
||||||
; jsr FindAnotherSprite2
|
|
||||||
jsr CalcSpriteEnd
|
|
||||||
; Update playfield
|
|
||||||
ldy PFIndex
|
|
||||||
lda (PF0Ptr),y ; load PF0 -> X
|
|
||||||
tax
|
tax
|
||||||
lda (PF1Ptr),y ; load PF1 -> tmp
|
lda (PData1),y ; bitmap for first line
|
||||||
sta tmpPF1
|
|
||||||
lda (PF2Ptr),y ; load PF2 -> Y
|
|
||||||
tay
|
tay
|
||||||
; Apply fine offsets
|
; WSYNC and store sprite values
|
||||||
TIMER_WAIT ; wait for 8th scanlines and WSYNC
|
lda Colp0
|
||||||
sta HMOVE ; apply the previous fine position(s)
|
; still have about 30 cycles left...
|
||||||
sta HMCLR ; clear motion registers
|
sta WSYNC
|
||||||
; Store playfield registers
|
sty GRP1 ; GRP0 is also updated due to VDELP0 flag
|
||||||
stx PF0
|
stx COLUP1
|
||||||
lda tmpPF1
|
sta COLUP0
|
||||||
sta PF1
|
; Return to caller
|
||||||
sty PF2
|
rts
|
||||||
dec PFIndex ; no more playfield?
|
|
||||||
bpl .KernelLoop
|
|
||||||
jmp .NoMoreLines
|
|
||||||
|
|
||||||
CalcSpriteEnd subroutine
|
CalcSpriteEnd subroutine
|
||||||
; Calculate # of lines to draw for each sprite
|
; Calculate # of lines to draw for each sprite
|
||||||
|
@ -355,16 +411,24 @@ CalcSpriteEnd subroutine
|
||||||
; Compute the number of 8x lines in this section
|
; Compute the number of 8x lines in this section
|
||||||
eor #$ff
|
eor #$ff
|
||||||
clc
|
clc
|
||||||
adc #5
|
adc #1
|
||||||
lsr
|
lsr
|
||||||
lsr
|
lsr
|
||||||
sta PFCount
|
sta PFCount
|
||||||
rts
|
rts
|
||||||
|
|
||||||
;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;; COMMON ROUTINES
|
|
||||||
;;;
|
; COMMON ROUTINES
|
||||||
|
|
||||||
|
ResetCounters subroutine
|
||||||
|
ldx #0
|
||||||
|
stx SSize0
|
||||||
|
stx SSize1
|
||||||
|
stx SIndx0
|
||||||
|
stx SIndx1
|
||||||
|
rts
|
||||||
|
|
||||||
; We were too late to display a sprite.
|
; We were too late to display a sprite.
|
||||||
; Put it earlier in the sort order and try next frame.
|
; Put it earlier in the sort order and try next frame.
|
||||||
; X = sort index
|
; X = sort index
|
||||||
|
@ -406,6 +470,7 @@ FindAnotherSprite2 ; alternate entry point when scanline known
|
||||||
; Due to timing issues, we have artifacts if player 1 is
|
; Due to timing issues, we have artifacts if player 1 is
|
||||||
; too close to the left edge of the screen. So we'd prefer to
|
; too close to the left edge of the screen. So we'd prefer to
|
||||||
; put those sprites in the player 0 slot.
|
; put those sprites in the player 0 slot.
|
||||||
|
; TODO: disable for 2-line sprite kernel
|
||||||
cmp #34 ; X < 34
|
cmp #34 ; X < 34
|
||||||
bcc .Plyr1NotReady
|
bcc .Plyr1NotReady
|
||||||
; First let's set its horizontal offset
|
; First let's set its horizontal offset
|
||||||
|
@ -436,7 +501,7 @@ FindAnotherSprite2 ; alternate entry point when scanline known
|
||||||
ldy #0
|
ldy #0
|
||||||
lda (PColr1),y
|
lda (PColr1),y
|
||||||
sta SSize1
|
sta SSize1
|
||||||
inc SSize1 ; +1 to size
|
inc SSize1 ; +1 to height
|
||||||
jmp .SetupDone
|
jmp .SetupDone
|
||||||
.Plyr1NotReady
|
.Plyr1NotReady
|
||||||
ldx SIndx0
|
ldx SIndx0
|
||||||
|
@ -465,47 +530,12 @@ FindAnotherSprite2 ; alternate entry point when scanline known
|
||||||
ldy #0
|
ldy #0
|
||||||
lda (PColr0),y
|
lda (PColr0),y
|
||||||
sta SSize0
|
sta SSize0
|
||||||
inc SSize0 ; +1 to size
|
inc SSize0 ; +1 to height
|
||||||
.SetupDone
|
.SetupDone
|
||||||
inc CurIndex ; go to next sprite in sort order
|
inc CurIndex ; go to next sprite in sort order
|
||||||
.NoNearSprite
|
.NoNearSprite
|
||||||
rts
|
rts
|
||||||
|
|
||||||
; called by 2-line kernel
|
|
||||||
DrawSprites2 subroutine
|
|
||||||
; Fetch sprite 0 values
|
|
||||||
lda SSize0 ; height in 2xlines
|
|
||||||
sec
|
|
||||||
isb SIndx0 ; INC yp0, then SBC yp0
|
|
||||||
bcs DoDraw0 ; inside bounds?
|
|
||||||
lda #0 ; no, load the padding offset (0)
|
|
||||||
DoDraw0
|
|
||||||
tay ; -> Y
|
|
||||||
lda (PColr0),y ; color for both lines
|
|
||||||
sta Colp0 ; -> colp0
|
|
||||||
lda (PData0),y ; bitmap for first line
|
|
||||||
sta GRP0 ; -> [GRP0] (delayed due to VDEL)
|
|
||||||
; Fetch sprite 1 values
|
|
||||||
lda SSize1 ; height in 2xlines
|
|
||||||
sec
|
|
||||||
isb SIndx1 ; INC yp0, then SBC yp0
|
|
||||||
bcs DoDraw1 ; inside bounds?
|
|
||||||
lda #0 ; no, load the padding offset (0)
|
|
||||||
DoDraw1
|
|
||||||
tay ; -> Y
|
|
||||||
lda (PColr1),y ; color for both lines
|
|
||||||
tax
|
|
||||||
lda (PData1),y ; bitmap for first line
|
|
||||||
tay
|
|
||||||
; WSYNC and store sprite values
|
|
||||||
lda Colp0
|
|
||||||
sta WSYNC
|
|
||||||
sty GRP1 ; GRP0 is also updated due to VDELP0 flag
|
|
||||||
stx COLUP1
|
|
||||||
sta COLUP0
|
|
||||||
; Return to caller
|
|
||||||
rts
|
|
||||||
|
|
||||||
; Perform one sort iteration
|
; Perform one sort iteration
|
||||||
; X register contains sort index (0 to NSprites-1)
|
; X register contains sort index (0 to NSprites-1)
|
||||||
SwapSprites subroutine
|
SwapSprites subroutine
|
||||||
|
|
40
presets/verilog/switches.v
Normal file
40
presets/verilog/switches.v
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
|
||||||
|
`include "hvsync_generator.v"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Player 1 Keys: arrow keys + space + shift
|
||||||
|
Player 2 Keys: A/D/W/S + Z + X
|
||||||
|
*/
|
||||||
|
module switches_top(clk, reset, hsync, vsync,
|
||||||
|
switches_p1, switches_p2,
|
||||||
|
rgb);
|
||||||
|
|
||||||
|
input clk, reset;
|
||||||
|
input [7:0] switches_p1;
|
||||||
|
input [7:0] switches_p2;
|
||||||
|
output hsync, vsync;
|
||||||
|
output [2:0] rgb;
|
||||||
|
wire display_on;
|
||||||
|
wire [8:0] hpos;
|
||||||
|
wire [8:0] vpos;
|
||||||
|
|
||||||
|
hvsync_generator hvsync_gen(
|
||||||
|
.clk(clk),
|
||||||
|
.reset(reset),
|
||||||
|
.hsync(hsync),
|
||||||
|
.vsync(vsync),
|
||||||
|
.display_on(display_on),
|
||||||
|
.hpos(hpos),
|
||||||
|
.vpos(vpos)
|
||||||
|
);
|
||||||
|
|
||||||
|
// select p1 bit based on vertical position
|
||||||
|
wire p1gfx = switches_p1[vpos[7:5]];
|
||||||
|
// select p2 bit based on horizontal position
|
||||||
|
wire p2gfx = switches_p2[hpos[7:5]];
|
||||||
|
|
||||||
|
assign rgb = {1'b0,
|
||||||
|
display_on && p1gfx,
|
||||||
|
display_on && p2gfx};
|
||||||
|
|
||||||
|
endmodule
|
|
@ -2,6 +2,8 @@
|
||||||
import { RAM, RasterVideo, dumpRAM, lookupSymbol } from "./emu";
|
import { RAM, RasterVideo, dumpRAM, lookupSymbol } from "./emu";
|
||||||
import { hex } from "./util";
|
import { hex } from "./util";
|
||||||
import { CodeAnalyzer } from "./analysis";
|
import { CodeAnalyzer } from "./analysis";
|
||||||
|
import { disassemble6502 } from "./cpu/disasm6502";
|
||||||
|
import { disassembleZ80 } from "./cpu/disasmz80";
|
||||||
|
|
||||||
declare var Z80_fast, jt, CPU6809;
|
declare var Z80_fast, jt, CPU6809;
|
||||||
|
|
||||||
|
@ -523,6 +525,9 @@ export abstract class BaseZ80Platform extends BaseDebugPlatform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
disassemble(pc:number, read:(addr:number)=>number) : DisasmLine {
|
||||||
|
return disassembleZ80(pc, read(pc), read(pc+1), read(pc+2), read(pc+3));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getToolForFilename_z80(fn) {
|
export function getToolForFilename_z80(fn) {
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
|
||||||
|
import { hex } from "../util";
|
||||||
|
|
||||||
var OPS_6502 = [
|
var OPS_6502 = [
|
||||||
{mn:"BRK",am:"",nb:1,il:0,c1:7,c2:0}, // 00
|
{mn:"BRK",am:"",nb:1,il:0,c1:7,c2:0}, // 00
|
||||||
{mn:"ORA",am:"(aa,x)",nb:2,il:0,c1:6,c2:0}, // 01
|
{mn:"ORA",am:"(aa,x)",nb:2,il:0,c1:6,c2:0}, // 01
|
||||||
|
@ -258,24 +260,7 @@ var OPS_6502 = [
|
||||||
{mn:"ISB",am:"AAAA,x",nb:3,il:1,c1:7,c2:1}, // FF
|
{mn:"ISB",am:"AAAA,x",nb:3,il:1,c1:7,c2:1}, // FF
|
||||||
];
|
];
|
||||||
|
|
||||||
function disassemble6502(pc:number, b0:number, b1:number, b2:number) : {line:string, nbytes:number} {
|
export function disassemble6502(pc:number, b0:number, b1:number, b2:number) : {line:string, nbytes:number} {
|
||||||
|
|
||||||
function formatHex(number, len) {
|
|
||||||
if (typeof number === "undefined" || number === null || isNaN(number)) {
|
|
||||||
throw new Error("Invalid value \"" + number + "\" passed to formatHex()");
|
|
||||||
}
|
|
||||||
var str = number.toString(16).toUpperCase();
|
|
||||||
if (!len) {
|
|
||||||
if (str.length % 2 == 1) {
|
|
||||||
len = str.length+1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (str.length < len) {
|
|
||||||
str = "0" + str;
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var op = OPS_6502[b0];
|
var op = OPS_6502[b0];
|
||||||
var s = op.mn;
|
var s = op.mn;
|
||||||
|
@ -283,10 +268,10 @@ function disassemble6502(pc:number, b0:number, b1:number, b2:number) : {line:str
|
||||||
if (am == 'branch') {
|
if (am == 'branch') {
|
||||||
var offset = (b1 < 0x80) ? (pc+2+b1) : (pc+2-(256-b1));
|
var offset = (b1 < 0x80) ? (pc+2+b1) : (pc+2-(256-b1));
|
||||||
offset &= 0xffff;
|
offset &= 0xffff;
|
||||||
am = '$'+formatHex(offset, 4);
|
am = '$'+hex(offset, 4);
|
||||||
} else {
|
} else {
|
||||||
am = am.replace('aa','$'+formatHex(b1, 2));
|
am = am.replace('aa','$'+hex(b1, 2));
|
||||||
am = am.replace('AAAA','$'+formatHex(b1+(b2<<8), 4));
|
am = am.replace('AAAA','$'+hex(b1+(b2<<8), 4));
|
||||||
}
|
}
|
||||||
return {line:op.mn + " " + am, nbytes:op.nb};
|
return {line:op.mn + " " + am, nbytes:op.nb};
|
||||||
};
|
};
|
||||||
|
|
72
src/cpu/disasmz80.ts
Normal file
72
src/cpu/disasmz80.ts
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
|
||||||
|
import { hex } from "../util";
|
||||||
|
|
||||||
|
const Z80_OPS = ["nop","ld bc,xx","ld (bc),a","inc bc","inc b","dec b","ld b,x","rlca","ex af,af'","add hl,bc","ld a,(bc)","dec bc","inc c","dec c","ld c,x","rrca","djnz x","ld de,xx","ld (de),a","inc de","inc d","dec d","ld d,x","rla","jr x","add hl,de","ld a,(de)","dec de","inc e","dec e","ld e,x","rra","jr nz,x","ld hl,xx","ld (xx),hl","inc hl","inc h","dec h","ld h,x","daa","jr z,x","add hl,hl","ld hl,(xx)","dec hl","inc l","dec l","ld l,x","cpl","jr nc,x","ld sp,xx","ld (xx),a","inc sp","inc (hl)","dec (hl)","ld (hl),x","scf","jr c,x","add hl,sp","ld a,(xx)","dec sp","inc a","dec a","ld a,x","ccf","ld b,b","ld b,c","ld b,d","ld b,e","ld b,h","ld b,l","ld b,(hl)","ld b,a","ld c,b","ld c,c","ld c,d","ld c,e","ld c,h","ld c,l","ld c,(hl)","ld c,a","ld d,b","ld d,c","ld d,d","ld d,e","ld d,h","ld d,l","ld d,(hl)","ld d,a","ld e,b","ld e,c","ld e,d","ld e,e","ld e,h","ld e,l","ld e,(hl)","ld e,a","ld h,b","ld h,c","ld h,d","ld h,e","ld h,h","ld h,l","ld h,(hl)","ld h,a","ld l,b","ld l,c","ld l,d","ld l,e","ld l,h","ld l,l","ld l,(hl)","ld l,a","ld (hl),b","ld (hl),c","ld (hl),d","ld (hl),e","ld (hl),h","ld (hl),l","","ld (hl),a","ld a,b","ld a,c","ld a,d","ld a,e","ld a,h","ld a,l","ld a,(hl)","ld a,a","add a,b","add a,c","add a,d","add a,e","add a,h","add a,l","add a,(hl)","add a,a","adc a,b","adc a,c","adc a,d","adc a,e","adc a,h","adc a,l","adc a,(hl)","adc a,a","sub b","sub c","sub d","sub e","sub h","sub l","sub (hl)","sub a","sbc a,b","sbc a,c","sbc a,d","sbc a,e","sbc a,h","sbc a,l","sbc a,(hl)","sbc a,a","and b","and c","and d","and e","and h","and l","and (hl)","and a","xor b","xor c","xor d","xor e","xor h","xor l","xor (hl)","xor a","or b","or c","or d","or e","or h","or l","or (hl)","or a","cp b","cp c","cp d","cp e","cp h","cp l","cp (hl)","cp a","ret nz","pop bc","jp nz,xx","jp xx","call nz,xx","push bc","add a,x","rst 00h","ret z","","jp z,xx","xxBITxx","call z,xx","call xx","adc a,x","rst 08h","ret nc","pop de","jp nc,xx","out (x),a","call nc,xx","push de","sub x","rst 10h","ret c","exx","jp c,xx","in a,(x)","call c,xx","xxIXxx","sbc a,x","rst 18h","ret po","pop hl","jp po,xx","ex (sp),hl","call po,xx","push hl","and x","rst 20h","ret pe","jp (hl)","jp pe,xx","ex de,hl","call pe,xx","xx80xx","xor x","rst 28h","ret p","pop af","jp p,xx","di","call p,xx","push af","or x","rst 30h","ret m","ld sp,hl","jp m,xx","ei","call m,xx","xxIYxx","cp x","rst 38h"];
|
||||||
|
const Z80_OPS_ED = ["in b,(c)","out (c),b","sbc hl,bc","ld (xx),bc","neg","retn","im 0","ld i,a","in c,(c)","out (c),c","adc hl,bc","ld bc,(xx)","neg","reti","","ld r,a","in d,(c)","out (c),d","sbc hl,de","ld (xx),de","neg","retn","im 1","ld a,i","in e,(c)","out (c),e","adc hl,de","ld de,(xx)","neg","retn","im 2","ld a,r","in h,(c)","out (c),h","sbc hl,hl","ld (xx),hl","neg","retn","","rrd","in l,(c)","out (c),l","adc hl,hl","ld hl,(xx)","neg","retn","","rld","in f,(c)","out (c),f","sbc hl,sp","ld (xx),sp","neg","retn","","","in a,(c)","out (c),a","adc hl,sp","ld sp,(xx)","neg","reti","","","ldi","cpi","ini","outi","","","","","ldd","cpd","ind","outd","","","","","ldir","cpir","inir","otir","","","","","lddr","cpdr","indr","otdr","","","",""];
|
||||||
|
const Z80_OPS_CB = ["rlc b","rlc c","rlc d","rlc e","rlc h","rlc l","rlc (hl)","rlc a","rrc b","rrc c","rrc d","rrc e","rrc h","rrc l","rrc (hl)","rrc a","rl b","rl c","rl d","rl e","rl h","rl l","rl (hl)","rl a","rr b","rr c","rr d","rr e","rr h","rr l","rr (hl)","rr a","sla b","sla c","sla d","sla e","sla h","sla l","sla (hl)","sla a","sra b","sra c","sra d","sra e","sra h","sra l","sra (hl)","sra a","sll b","sll c","sll d","sll e","sll h","sll l","sll (hl)","sll a","srl b","srl c","srl d","srl e","srl h","srl l","srl (hl)","srl a","bit 0,b","bit 0,c","bit 0,d","bit 0,e","bit 0,h","bit 0,l","bit 0,(hl)","bit 0,a","bit 1,b","bit 1,c","bit 1,d","bit 1,e","bit 1,h","bit 1,l","bit 1,(hl)","bit 1,a","bit 2,b","bit 2,c","bit 2,d","bit 2,e","bit 2,h","bit 2,l","bit 2,(hl)","bit 2,a","bit 3,b","bit 3,c","bit 3,d","bit 3,e","bit 3,h","bit 3,l","bit 3,(hl)","bit 3,a","bit 4,b","bit 4,c","bit 4,d","bit 4,e","bit 4,h","bit 4,l","bit 4,(hl)","bit 4,a","bit 5,b","bit 5,c","bit 5,d","bit 5,e","bit 5,h","bit 5,l","bit 5,(hl)","bit 5,a","bit 6,b","bit 6,c","bit 6,d","bit 6,e","bit 6,h","bit 6,l","bit 6,(hl)","bit 6,a","bit 7,b","bit 7,c","bit 7,d","bit 7,e","bit 7,h","bit 7,l","bit 7,(hl)","bit 7,a","res 0,b","res 0,c","res 0,d","res 0,e","res 0,h","res 0,l","res 0,(hl)","res 0,a","res 1,b","res 1,c","res 1,d","res 1,e","res 1,h","res 1,l","res 1,(hl)","res 1,a","res 2,b","res 2,c","res 2,d","res 2,e","res 2,h","res 2,l","res 2,(hl)","res 2,a","res 3,b","res 3,c","res 3,d","res 3,e","res 3,h","res 3,l","res 3,(hl)","res 3,a","res 4,b","res 4,c","res 4,d","res 4,e","res 4,h","res 4,l","res 4,(hl)","res 4,a","res 5,b","res 5,c","res 5,d","res 5,e","res 5,h","res 5,l","res 5,(hl)","res 5,a","res 6,b","res 6,c","res 6,d","res 6,e","res 6,h","res 6,l","res 6,(hl)","res 6,a","res 7,b","res 7,c","res 7,d","res 7,e","res 7,h","res 7,l","res 7,(hl)","res 7,a","set 0,b","set 0,c","set 0,d","set 0,e","set 0,h","set 0,l","set 0,(hl)","set 0,a","set 1,b","set 1,c","set 1,d","set 1,e","set 1,h","set 1,l","set 1,(hl)","set 1,a","set 2,b","set 2,c","set 2,d","set 2,e","set 2,h","set 2,l","set 2,(hl)","set 2,a","set 3,b","set 3,c","set 3,d","set 3,e","set 3,h","set 3,l","set 3,(hl)","set 3,a","set 4,b","set 4,c","set 4,d","set 4,e","set 4,h","set 4,l","set 4,(hl)","set 4,a","set 5,b","set 5,c","set 5,d","set 5,e","set 5,h","set 5,l","set 5,(hl)","set 5,a","set 6,b","set 6,c","set 6,d","set 6,e","set 6,h","set 6,l","set 6,(hl)","set 6,a","set 7,b","set 7,c","set 7,d","set 7,e","set 7,h","set 7,l","set 7,(hl)","set 7,a"];
|
||||||
|
|
||||||
|
// TODO: DD, etc -- http://z80-heaven.wikidot.com/opcode-reference-chart
|
||||||
|
|
||||||
|
export function disassembleZ80(pc:number, b0:number, b1:number, b2:number, b3:number) : {line:string, nbytes:number} {
|
||||||
|
|
||||||
|
var op,n,am;
|
||||||
|
var bytes = [b0,b1,b2,b3];
|
||||||
|
n=1;
|
||||||
|
switch (b0) {
|
||||||
|
case 0xcb:
|
||||||
|
am = Z80_OPS_CB[b1];
|
||||||
|
n++;
|
||||||
|
break;
|
||||||
|
case 0xed:
|
||||||
|
if (b1 >= 0x40 && b1 <= 0x7f) am = Z80_OPS_ED[b1 - 0x40];
|
||||||
|
if (b1 >= 0xa0 && b1 <= 0xbf) am = Z80_OPS_ED[b1 - 0xa0 + 0x40];
|
||||||
|
n++;
|
||||||
|
break;
|
||||||
|
case 0xdd:
|
||||||
|
am = Z80_OPS[b1].replace(/\bhl\b/, 'ix');
|
||||||
|
n++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
am = Z80_OPS[b0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!am || !am.length) am = "??";
|
||||||
|
if (am.indexOf('xx') >= 0) {
|
||||||
|
am = am.replace(/\bxx\b/,'$'+hex(bytes[n]+(bytes[n+1]<<8), 4));
|
||||||
|
n += 2;
|
||||||
|
} else if (am.indexOf('x') >= 0) {
|
||||||
|
if (am.startsWith('j')) {
|
||||||
|
var offset = (b1 < 0x80) ? (pc+2+b1) : (pc+2-(256-b1));
|
||||||
|
offset &= 0xffff;
|
||||||
|
am = am.replace(/\bx\b/,'$'+hex(offset, 4));
|
||||||
|
} else {
|
||||||
|
am = am.replace(/\bx\b/,'$'+hex(bytes[n], 2));
|
||||||
|
}
|
||||||
|
n += 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if (b0 == 0xcd && (s = cb_prefixed_ops[b1])) {
|
||||||
|
n = 2;
|
||||||
|
} else if (s = one_byte_instructions[b0]) {
|
||||||
|
n = 1;
|
||||||
|
} else if (s = two_byte_instructions[b0]) {
|
||||||
|
n = 2;
|
||||||
|
} else if (s = three_byte_instructions[b0]) {
|
||||||
|
n = 3;
|
||||||
|
} else {
|
||||||
|
s = "??";
|
||||||
|
n = 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
TODO: http://z80-heaven.wikidot.com/opcode-reference-chart
|
||||||
|
if (am == 'branch') {
|
||||||
|
var offset = (b1 < 0x80) ? (pc+2+b1) : (pc+2-(256-b1));
|
||||||
|
offset &= 0xffff;
|
||||||
|
am = '$'+formatHex(offset, 4);
|
||||||
|
} else {
|
||||||
|
am = am.replace('aa','$'+formatHex(b1, 2));
|
||||||
|
am = am.replace('AAAA','$'+formatHex(b1+(b2<<8), 4));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return {line:am.toUpperCase(), nbytes:n};
|
||||||
|
};
|
|
@ -4,11 +4,16 @@ import { Platform, BasePlatform, cpuStateToLongString_6502, BaseMAMEPlatform, Em
|
||||||
import { PLATFORMS, RAM, newAddressDecoder, dumpRAM } from "../emu";
|
import { PLATFORMS, RAM, newAddressDecoder, dumpRAM } from "../emu";
|
||||||
import { hex, lpad, tobin, byte2signed } from "../util";
|
import { hex, lpad, tobin, byte2signed } from "../util";
|
||||||
import { CodeAnalyzer_vcs } from "../analysis";
|
import { CodeAnalyzer_vcs } from "../analysis";
|
||||||
|
import { disassemble6502 } from "../cpu/disasm6502";
|
||||||
|
|
||||||
declare var platform : Platform; // global platform object
|
declare var platform : Platform; // global platform object
|
||||||
declare var Javatari : any;
|
declare var Javatari : any;
|
||||||
declare var jt : any; // 6502
|
declare var jt : any; // 6502
|
||||||
|
|
||||||
|
// TODO: import or put in platform
|
||||||
|
declare var symbolmap : {[ident:string]:number};
|
||||||
|
declare var addr2symbol : {[addr:number]:string};
|
||||||
|
|
||||||
const VCS_PRESETS = [
|
const VCS_PRESETS = [
|
||||||
{id:'examples/hello', chapter:4, name:'Hello 6502 and TIA'},
|
{id:'examples/hello', chapter:4, name:'Hello 6502 and TIA'},
|
||||||
{id:'examples/vsync', chapter:5, name:'Painting on the CRT', title:'Color Bars'},
|
{id:'examples/vsync', chapter:5, name:'Painting on the CRT', title:'Color Bars'},
|
||||||
|
@ -38,7 +43,7 @@ const VCS_PRESETS = [
|
||||||
{id:'examples/wavetable', chapter:36, name:'Wavetable Sound'},
|
{id:'examples/wavetable', chapter:36, name:'Wavetable Sound'},
|
||||||
{id:'examples/fracpitch', name:'Fractional Pitch'},
|
{id:'examples/fracpitch', name:'Fractional Pitch'},
|
||||||
{id:'examples/pal', name:'PAL Video Output'},
|
{id:'examples/pal', name:'PAL Video Output'},
|
||||||
{id:'examples/testlibrary', name:'VCS Library Demo'},
|
// {id:'examples/testlibrary', name:'VCS Library Demo'},
|
||||||
// {id:'examples/music2', name:'Pitch-Accurate Music'},
|
// {id:'examples/music2', name:'Pitch-Accurate Music'},
|
||||||
// {id:'examples/fullgame', name:'Thru Hike: The Game', title:'Thru Hike'},
|
// {id:'examples/fullgame', name:'Thru Hike: The Game', title:'Thru Hike'},
|
||||||
];
|
];
|
||||||
|
@ -246,6 +251,22 @@ class VCSPlatform extends BasePlatform {
|
||||||
disassemble(pc:number, read:(addr:number)=>number) : DisasmLine {
|
disassemble(pc:number, read:(addr:number)=>number) : DisasmLine {
|
||||||
return disassemble6502(pc, read(pc), read(pc+1), read(pc+2));
|
return disassemble6502(pc, read(pc), read(pc+1), read(pc+2));
|
||||||
}
|
}
|
||||||
|
inspect(ident : string) : string {
|
||||||
|
if (this.isRunning()) return; // only inspect when stopped
|
||||||
|
var result;
|
||||||
|
var addr = symbolmap && (symbolmap[ident]); // || symbolmap['_'+ident]);
|
||||||
|
if (addr >= 0x80 && addr < 0x100) { // in RAM?
|
||||||
|
var size=4;
|
||||||
|
result = "$" + hex(addr,4) + ":";
|
||||||
|
for (var i=0; i<size; i++) {
|
||||||
|
var byte = platform.readAddress(addr+i);
|
||||||
|
result += " $" + hex(byte,2) + " (" + byte + ")";
|
||||||
|
if (addr2symbol[addr+1]) break; // stop if we hit another symbol
|
||||||
|
else if (i==size-1) result += " ...";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// TODO: mixin for Base6502Platform?
|
// TODO: mixin for Base6502Platform?
|
||||||
|
|
||||||
|
|
15
src/views.ts
15
src/views.ts
|
@ -112,19 +112,6 @@ export class SourceEditor implements ProjectView {
|
||||||
var result;
|
var result;
|
||||||
if (platform.inspect) {
|
if (platform.inspect) {
|
||||||
result = platform.inspect(ident);
|
result = platform.inspect(ident);
|
||||||
} else if (!platform.isRunning() && platform.readAddress) { // only inspect when stopped
|
|
||||||
// TODO: platform should know its symbols
|
|
||||||
var addr = symbolmap[ident];
|
|
||||||
if (addr) {
|
|
||||||
var size=4;
|
|
||||||
result = "$" + hex(addr,4) + ":";
|
|
||||||
for (var i=0; i<size; i++) {
|
|
||||||
var byte = platform.readAddress(addr+i);
|
|
||||||
result += " $" + hex(byte,2) + " (" + byte + ")";
|
|
||||||
if (addr2symbol[addr+1]) break; // stop if we hit another symbol
|
|
||||||
else if (i==size-1) result += " ...";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (this.inspectWidget) {
|
if (this.inspectWidget) {
|
||||||
this.inspectWidget.clear();
|
this.inspectWidget.clear();
|
||||||
|
@ -483,7 +470,7 @@ export class DisassemblerView implements ProjectView {
|
||||||
return substr;
|
return substr;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
var dline = hex(parseInt(a)) + "\t" + bytes + "\t" + dstr + "\n";
|
var dline = hex(parseInt(a), 4) + "\t" + bytes + "\t" + dstr + "\n";
|
||||||
s += dline;
|
s += dline;
|
||||||
if (a == pc) selline = curline;
|
if (a == pc) selline = curline;
|
||||||
curline++;
|
curline++;
|
||||||
|
|
|
@ -151,6 +151,13 @@ var PLATFORM_PARAMS = {
|
||||||
},
|
},
|
||||||
'verilog': {
|
'verilog': {
|
||||||
},
|
},
|
||||||
|
'astrocade': {
|
||||||
|
code_start: 0x2000,
|
||||||
|
rom_size: 0x2000,
|
||||||
|
data_start: 0x4e00,
|
||||||
|
data_size: 0x200,
|
||||||
|
stack_end: 0x5000,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// shim out window and document objects for security
|
// shim out window and document objects for security
|
||||||
|
@ -995,6 +1002,7 @@ function linkSDLDZ80(step)
|
||||||
var asmlines = parseListing(rstout, /^\s*([0-9A-F]+)\s+([0-9A-F][0-9A-F r]*[0-9A-F])\s+\[([0-9 ]+)\]\s+(\d+) (.*)/i, 4, 1, 2);
|
var asmlines = parseListing(rstout, /^\s*([0-9A-F]+)\s+([0-9A-F][0-9A-F r]*[0-9A-F])\s+\[([0-9 ]+)\]\s+(\d+) (.*)/i, 4, 1, 2);
|
||||||
var srclines = parseSourceLines(rstout, /^\s+\d+ ;<stdin>:(\d+):/i, /^\s*([0-9A-F]{4})/i);
|
var srclines = parseSourceLines(rstout, /^\s+\d+ ;<stdin>:(\d+):/i, /^\s*([0-9A-F]{4})/i);
|
||||||
putWorkFile(fn, rstout);
|
putWorkFile(fn, rstout);
|
||||||
|
// TODO: you have to get rid of all source lines to get asm listing
|
||||||
listings[fn] = {
|
listings[fn] = {
|
||||||
asmlines:srclines.length ? asmlines : null,
|
asmlines:srclines.length ? asmlines : null,
|
||||||
lines:srclines.length ? srclines : asmlines,
|
lines:srclines.length ? srclines : asmlines,
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
|
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var vm = require('vm');
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var includeInThisContext = function(path) {
|
|
||||||
var code = fs.readFileSync(path);
|
|
||||||
vm.runInThisContext(code, path);
|
|
||||||
};
|
|
||||||
|
|
||||||
includeInThisContext("gen/cpu/disasm6502.js");
|
var disassemble6502 = require("gen/cpu/disasm6502.js").disassemble6502;
|
||||||
|
|
||||||
describe('6502 disassembler', function() {
|
describe('6502 disassembler', function() {
|
||||||
it('Should work', function() {
|
it('Should work', function() {
|
||||||
|
|
18
test/cli/z80/testz80disasm.js
Normal file
18
test/cli/z80/testz80disasm.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
var assert = require('assert');
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
|
var disassembleZ80 = require("gen/cpu/disasmz80.js").disassembleZ80;
|
||||||
|
|
||||||
|
describe('Z80 disassembler', function() {
|
||||||
|
it('Should work', function() {
|
||||||
|
assert.deepEqual({line:"LD SP,$E800",nbytes:3}, disassembleZ80(0, 0x31, 0x00, 0xe8, 0));
|
||||||
|
assert.deepEqual({line:"DI",nbytes:1}, disassembleZ80(0, 0xF3, 0, 0, 0));
|
||||||
|
assert.deepEqual({line:"JP $0007",nbytes:3}, disassembleZ80(0, 0xC3, 0x07, 0x00, 0));
|
||||||
|
assert.deepEqual({line:"LD A,$01",nbytes:2}, disassembleZ80(0, 0x3E, 0x01, 0, 0));
|
||||||
|
assert.deepEqual({line:"LDIR",nbytes:2}, disassembleZ80(0, 0xED, 0xB0, 0, 0));
|
||||||
|
assert.deepEqual({line:"JR C,$0027",nbytes:2}, disassembleZ80(0x4e, 0x38, 0xD7, 0, 0));
|
||||||
|
assert.deepEqual({line:"XOR A",nbytes:2}, disassembleZ80(0, 0xaf, 0xd3, 0, 0));
|
||||||
|
assert.deepEqual({line:"LD IX,$41E0",nbytes:4}, disassembleZ80(0, 0xdd, 0x21, 0xe0, 0x41));
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user