mirror of
https://github.com/tomcw/Cybernoid.git
synced 2025-01-13 20:32:04 +00:00
Commit of v5 code
This commit is contained in:
commit
84ff354f52
13
Common/AppleDefs.a
Normal file
13
Common/AppleDefs.a
Normal file
@ -0,0 +1,13 @@
|
||||
IRQL = $3FE
|
||||
IRQH = $3FF
|
||||
|
||||
;--------------------------------------
|
||||
|
||||
SW_SLOTXROM_ENA = $C006
|
||||
SW_SLOTXROM_DIS = $C007
|
||||
SW_SLOTXROM_R = $C015 ; Active low
|
||||
|
||||
SW_SLOT3ROM_DIS = $C00A
|
||||
SW_SLOT3ROM_ENA = $C00B
|
||||
SW_SLOT3ROM_R = $C017 ; Active high
|
||||
|
440
Common/MB-Macros.a
Normal file
440
Common/MB-Macros.a
Normal file
@ -0,0 +1,440 @@
|
||||
|
||||
SPECTRUM128_STEREO = 1 ; L = A+Bx0.5, R = C'+B'x0.5
|
||||
DUAL_MONO = 0 ; L = A+B+C, R=A'+B'+C'
|
||||
|
||||
|
||||
!macro MB_Init1 .RegSongNum {
|
||||
; Pre: A = Song# [0..NUM_SONGS-1]
|
||||
; Post: .RegSongNum = Song#
|
||||
;
|
||||
|
||||
jmp .skip_data
|
||||
|
||||
nSongNum: !byte 0 ; Song#
|
||||
nFrameNum: !byte 0,0,0 ; Minute:Second:FrameNum (@ 50Hz)
|
||||
;
|
||||
nMaskA: !byte 0 ; Voice-A mask (0=enable)
|
||||
nMaskB: !byte 0 ; Voice-B mask (0=enable)
|
||||
nMaskC: !byte 0 ; Voice-C mask (0=enable)
|
||||
;
|
||||
nAttA: !byte 0 ; Attenuation of Voice-A
|
||||
nAttB: !byte 1 ; Attenuation of Voice-B : B Volume / 2 (logarithmic, so: if (A) A--)
|
||||
nAttC: !byte 0 ; Attenuation of Voice-C
|
||||
;
|
||||
pAYRegValues: !word AYRegValues ; For VU-meter
|
||||
|
||||
;
|
||||
|
||||
.skip_data:
|
||||
lda nSongNum
|
||||
cmp #NUM_SONGS
|
||||
bcc SongNumOK
|
||||
lda #255 ; Uninit
|
||||
sta nSongNum
|
||||
SongNumOK:
|
||||
|
||||
;
|
||||
|
||||
lda nMBBaseHi
|
||||
beq FindMB
|
||||
|
||||
; Need to disable Timer1 IRQ before:
|
||||
; . Scanning for MB card
|
||||
; . Saving ZPBlock
|
||||
|
||||
lda #1<<6
|
||||
MB0: sta CARD_BASE+SY6522_IER ; Disable Timer1 IRQ
|
||||
|
||||
FindMB:
|
||||
|
||||
;----------------------------------
|
||||
|
||||
+SaveRegs ZPBlock
|
||||
|
||||
jsr SF_GetMBSlot
|
||||
bne GotMBSlot
|
||||
|
||||
; MB not found!
|
||||
jmp InitExit2
|
||||
|
||||
GotMBSlot:
|
||||
; Setup correct address in IRQ handler code:
|
||||
|
||||
!if SPECTRUM128_STEREO {
|
||||
stx MBx1+2
|
||||
stx MBx2+2
|
||||
stx MBx3+2
|
||||
stx MBx4+2
|
||||
}
|
||||
|
||||
!if DUAL_MONO {
|
||||
stx MB1+2
|
||||
stx MB1b+2
|
||||
stx MB2+2
|
||||
stx MB2b+2
|
||||
stx MB3+2
|
||||
stx MB3b+2
|
||||
stx MB4+2
|
||||
stx MB4b+2
|
||||
stx MB5+2
|
||||
stx MB5b+2
|
||||
stx MB6+2
|
||||
stx MB6b+2
|
||||
}
|
||||
|
||||
stx MB0+2
|
||||
stx MB7+2
|
||||
|
||||
stx nMBBaseHi
|
||||
|
||||
;
|
||||
|
||||
lda #$07
|
||||
ldy #SY6522_DDRB
|
||||
sta (MBBase),y
|
||||
ldy #SY6522_DDRB+$80
|
||||
sta (MBBase),y
|
||||
|
||||
lda #$ff
|
||||
ldy #SY6522_DDRA
|
||||
sta (MBBase),y
|
||||
ldy #SY6522_DDRA+$80
|
||||
sta (MBBase),y
|
||||
|
||||
lda #AY_RESET
|
||||
ldy #SY6522_ORB
|
||||
sta (MBBase),y
|
||||
ldy #SY6522_ORB+$80
|
||||
sta (MBBase),y
|
||||
|
||||
ldx nSongNum
|
||||
cpx #255
|
||||
bne NotFini
|
||||
|
||||
jmp InitExit
|
||||
|
||||
NotFini:
|
||||
lda SongTbl,x
|
||||
sta .RegSongNum
|
||||
}
|
||||
|
||||
;--------------------------------------
|
||||
|
||||
!macro MB_Init2 {
|
||||
lda #0
|
||||
sta nFrameNum+0
|
||||
sta nFrameNum+1
|
||||
sta nFrameNum+2
|
||||
|
||||
; Setup Timer1 IRQ to trigger at 50Hz
|
||||
; Apple CLK = 1.022727 MHz, so set Timer1=0x4fe7
|
||||
|
||||
sei
|
||||
|
||||
lda #$e7
|
||||
ldy #SY6522_TIMER1L_COUNTER
|
||||
sta (MBBase),y
|
||||
lda #$4f
|
||||
ldy #SY6522_TIMER1H_COUNTER
|
||||
sta (MBBase),y
|
||||
|
||||
lda #1<<6
|
||||
ldy #SY6522_ACR
|
||||
sta (MBBase),y ; Free running timer
|
||||
|
||||
lda #1<<7 | 1<<6
|
||||
ldy #SY6522_IER
|
||||
sta (MBBase),y ; Enable Timer1 IRQ
|
||||
|
||||
lda #<Interrupt ; ADDR_L
|
||||
sta IRQL
|
||||
lda #>Interrupt ; ADDR_H
|
||||
sta IRQH
|
||||
|
||||
InitExit:
|
||||
cli
|
||||
|
||||
+SaveRegs Z80Block
|
||||
|
||||
InitExit2:
|
||||
+RestoreRegs ZPBlock
|
||||
}
|
||||
|
||||
;--------------------------------------
|
||||
|
||||
!macro SF_UpdateAY {
|
||||
|
||||
; Skyfox's routine to update AY regs:
|
||||
|
||||
SF_SelectReg:
|
||||
MBx1: sta CARD_BASE+SY6522_ORA,x
|
||||
lda #AY_LATCH
|
||||
bne .l675e
|
||||
|
||||
SF_WriteReg:
|
||||
MBx2: sta CARD_BASE+SY6522_ORA,x
|
||||
lda #AY_WRITE
|
||||
bne .l675e
|
||||
|
||||
SF_ChipReset:
|
||||
lda #AY_RESET
|
||||
|
||||
.l675e:
|
||||
MBx3: sta CARD_BASE+SY6522_ORB,x
|
||||
lda #AY_INACTIVE
|
||||
MBx4: sta CARD_BASE+SY6522_ORB,x
|
||||
rts
|
||||
}
|
||||
|
||||
;--------------------------------------
|
||||
|
||||
!if SPECTRUM128_STEREO {
|
||||
; L = A+Bx0.5, R = C'+B'x0.5
|
||||
;
|
||||
|
||||
!macro MB_WriteAYRegs .ay_regs_base {
|
||||
; Enable SLOTXROM while accessing MB regs
|
||||
lda SW_SLOTXROM_R
|
||||
pha
|
||||
bpl .ay_init ; branch if b7=0 (enabled)
|
||||
sta SW_SLOTXROM_ENA
|
||||
|
||||
.ay_init:
|
||||
ldy #$0D
|
||||
|
||||
.ay_loop:
|
||||
lda .ay_regs_base,y
|
||||
|
||||
cpy #AY_ENABLE
|
||||
bne .ay_cont
|
||||
|
||||
tax ; Save AY_ENABLE
|
||||
ora #AY_DIS_C
|
||||
sta .ay0_regs,y
|
||||
|
||||
txa ; Restore AY_ENABLE
|
||||
ora #AY_DIS_A
|
||||
sta .ay1_regs,y
|
||||
|
||||
dey
|
||||
bpl .ay_loop ; branch always taken
|
||||
|
||||
;
|
||||
|
||||
.ay_cont:
|
||||
sta .ay0_regs,y
|
||||
sta .ay1_regs,y
|
||||
dey
|
||||
bpl .ay_loop
|
||||
|
||||
;
|
||||
|
||||
; Post processing
|
||||
AYPostProc:
|
||||
lda #0
|
||||
sta .ay1_regs+AY_AVOL
|
||||
sta .ay0_regs+AY_CVOL
|
||||
|
||||
;
|
||||
; Attenuate AVOL
|
||||
|
||||
lda .ay_regs_base+AY_AVOL
|
||||
sec
|
||||
sbc nAttA
|
||||
bpl .ay_set_a_vol
|
||||
lda #0
|
||||
.ay_set_a_vol
|
||||
sta .ay0_regs+AY_AVOL
|
||||
|
||||
;
|
||||
; Attenuate BVOL
|
||||
|
||||
lda .ay_regs_base+AY_BVOL
|
||||
sec
|
||||
sbc nAttB
|
||||
bpl .ay_set_b_vol
|
||||
lda #0
|
||||
.ay_set_b_vol
|
||||
sta .ay0_regs+AY_BVOL
|
||||
sta .ay1_regs+AY_BVOL
|
||||
|
||||
;
|
||||
; Attenuate CVOL
|
||||
|
||||
lda .ay_regs_base+AY_CVOL
|
||||
sec
|
||||
sbc nAttC
|
||||
bpl .ay_set_c_vol
|
||||
lda #0
|
||||
.ay_set_c_vol
|
||||
sta .ay1_regs+AY_CVOL
|
||||
|
||||
;
|
||||
; User disable A/B/C
|
||||
|
||||
.ay_chk_maska:
|
||||
lda nMaskA
|
||||
beq .ay_chk_maskb
|
||||
lda #0
|
||||
sta .ay0_regs+AY_AVOL
|
||||
|
||||
lda .ay0_regs+AY_ENABLE
|
||||
ora #AY_DIS_A
|
||||
sta .ay0_regs+AY_ENABLE
|
||||
|
||||
.ay_chk_maskb:
|
||||
lda nMaskB
|
||||
beq .ay_chk_maskc
|
||||
lda #0
|
||||
sta .ay0_regs+AY_BVOL
|
||||
sta .ay1_regs+AY_BVOL
|
||||
|
||||
lda .ay0_regs+AY_ENABLE
|
||||
ora #AY_DIS_B
|
||||
sta .ay0_regs+AY_ENABLE
|
||||
|
||||
lda .ay1_regs+AY_ENABLE
|
||||
ora #AY_DIS_B
|
||||
sta .ay1_regs+AY_ENABLE
|
||||
|
||||
.ay_chk_maskc:
|
||||
lda nMaskC
|
||||
beq .ay_chk_mask_done
|
||||
lda #0
|
||||
sta .ay1_regs+AY_CVOL
|
||||
|
||||
lda .ay1_regs+AY_ENABLE
|
||||
ora #AY_DIS_C
|
||||
sta .ay1_regs+AY_ENABLE
|
||||
|
||||
.ay_chk_mask_done:
|
||||
|
||||
;
|
||||
|
||||
ldx #0
|
||||
ldy #$0D
|
||||
.sf_loop0: tya
|
||||
jsr SF_SelectReg
|
||||
lda .ay0_regs,y
|
||||
jsr SF_WriteReg
|
||||
dey
|
||||
bpl .sf_loop0
|
||||
|
||||
;
|
||||
|
||||
ldx #$80
|
||||
ldy #$0D
|
||||
.sf_loop1: tya
|
||||
jsr SF_SelectReg
|
||||
lda .ay1_regs,y
|
||||
jsr SF_WriteReg
|
||||
dey
|
||||
bpl .sf_loop1
|
||||
|
||||
; Disable SLOTXROM if necessary
|
||||
pla
|
||||
bpl .ay_done ; branch if b7=0 (enabled)
|
||||
sta SW_SLOTXROM_DIS
|
||||
bmi .ay_done ; branch always taken
|
||||
|
||||
;--------------
|
||||
|
||||
.ay0_regs: !fill 14,0
|
||||
.ay1_regs: !fill 14,0
|
||||
|
||||
+SF_UpdateAY
|
||||
|
||||
;--------------
|
||||
|
||||
.ay_done:
|
||||
|
||||
}
|
||||
} ; !if SPECTRUM128_STEREO
|
||||
|
||||
;------------------
|
||||
|
||||
!if DUAL_MONO {
|
||||
; L = A+B+C, R=A'+B'+C'
|
||||
;
|
||||
|
||||
!macro MB_WriteAYRegs .ay_regs_base {
|
||||
; Enable SLOTXROM while accessing MB regs
|
||||
lda SW_SLOTXROM_R
|
||||
pha
|
||||
bpl .ay_init ; branch if b7=0 (enabled)
|
||||
sta SW_SLOTXROM_ENA
|
||||
|
||||
.ay_init:
|
||||
ldy #$0D
|
||||
lda #<.ay_regs_base
|
||||
sta TmpL
|
||||
lda #>.ay_regs_base
|
||||
sta TmpH
|
||||
|
||||
.ay_loop:
|
||||
; Select AY reg
|
||||
MB1: sty CARD_BASE+SY6522_ORA
|
||||
MB1b: sty CARD_BASE+SY6522_ORA+$80
|
||||
lda #$07 ; LATCH
|
||||
MB2: sta CARD_BASE+SY6522_ORB
|
||||
MB2b: sta CARD_BASE+SY6522_ORB+$80
|
||||
lda #$04 ; INACTIVE
|
||||
MB3: sta CARD_BASE+SY6522_ORB
|
||||
MB3b: sta CARD_BASE+SY6522_ORB+$80
|
||||
|
||||
; Write AY reg
|
||||
lda (TmpL),y
|
||||
MB4: sta CARD_BASE+SY6522_ORA
|
||||
MB4b: sta CARD_BASE+SY6522_ORA+$80
|
||||
lda #$06 ; WRITE
|
||||
MB5: sta CARD_BASE+SY6522_ORB
|
||||
MB5b: sta CARD_BASE+SY6522_ORB+$80
|
||||
lda #$04 ; INACTIVE
|
||||
MB6: sta CARD_BASE+SY6522_ORB
|
||||
MB6b: sta CARD_BASE+SY6522_ORB+$80
|
||||
|
||||
dey
|
||||
bpl .ay_loop
|
||||
|
||||
; Disable SLOTXROM if necessary
|
||||
pla
|
||||
bpl .ay_done ; branch if b7=0 (enabled)
|
||||
sta SW_SLOTXROM_DIS
|
||||
|
||||
.ay_done:
|
||||
}
|
||||
} ; !if DUAL_MONO
|
||||
|
||||
;--------------------------------------
|
||||
|
||||
!macro MB_ISR .isr_main {
|
||||
; Pre:
|
||||
; 6502 has pushed P
|
||||
; Apple ROM has stored A to $45 (not Apple //e ROM!)
|
||||
;
|
||||
|
||||
txa
|
||||
pha
|
||||
tya
|
||||
pha
|
||||
|
||||
+SaveRegs ZPBlock
|
||||
+RestoreRegs Z80Block
|
||||
|
||||
jsr .isr_main
|
||||
|
||||
+SaveRegs Z80Block
|
||||
+RestoreRegs ZPBlock
|
||||
|
||||
lda #1<<6
|
||||
MB7:
|
||||
sta CARD_BASE+SY6522_IFR ; Clear Timer1 IRQ flag
|
||||
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
|
||||
lda $45
|
||||
rti
|
||||
}
|
45
Common/MockingboardDefs.a
Normal file
45
Common/MockingboardDefs.a
Normal file
@ -0,0 +1,45 @@
|
||||
; Mockingboard defines:
|
||||
|
||||
CARD_BASE = $C100
|
||||
|
||||
SY6522_ORB = 0
|
||||
SY6522_ORA = 1
|
||||
SY6522_DDRB = 2
|
||||
SY6522_DDRA = 3
|
||||
SY6522_TIMER1L_COUNTER = 4
|
||||
SY6522_TIMER1H_COUNTER = 5
|
||||
SY6522_TIMER2L_COUNTER = 8
|
||||
SY6522_TIMER2H_COUNTER = 9
|
||||
SY6522_ACR = $B
|
||||
SY6522_IFR = $D
|
||||
SY6522_IER = $E
|
||||
|
||||
AY_AFINE = 0
|
||||
AY_ACOARSE = 1
|
||||
AY_BFINE = 2
|
||||
AY_BCOARSE = 3
|
||||
AY_CFINE = 4
|
||||
AY_CCOARSE = 5
|
||||
AY_NOISEPER = 6
|
||||
AY_ENABLE = 7
|
||||
AY_AVOL = 8
|
||||
AY_BVOL = 9
|
||||
AY_CVOL = 10
|
||||
AY_EFINE = 11
|
||||
AY_ECOARSE = 12
|
||||
AY_ESHAPE = 13
|
||||
|
||||
AY_ENA_A = %110110 ; Enable A (Noise & Tone)
|
||||
AY_ENA_B = %101101 ; Enable B (Noise & Tone)
|
||||
AY_ENA_C = %011011 ; Enable C (Noise & Tone)
|
||||
|
||||
AY_DIS_A = %001001 ; Disable A (Noise & Tone)
|
||||
AY_DIS_B = %010010 ; Disable B (Noise & Tone)
|
||||
AY_DIS_C = %100100 ; Disable C (Noise & Tone)
|
||||
|
||||
; AY inputs on BDIR|BC2|BC1:
|
||||
AY_RESET = 0
|
||||
AY_INACTIVE = 4
|
||||
AY_READ = 5
|
||||
AY_WRITE = 6
|
||||
AY_LATCH = 7
|
260
Common/Z80-Macros.a
Normal file
260
Common/Z80-Macros.a
Normal file
@ -0,0 +1,260 @@
|
||||
; 6502 -> Z80 macros
|
||||
;
|
||||
|
||||
; C flag differences:
|
||||
;
|
||||
; A=1, A=2, A=3,
|
||||
; CMP #2: CMP #2: CMP #2:
|
||||
; SCZ SCZ SCZ
|
||||
; 6502: 100 011 010
|
||||
; Z80: 110 001 000
|
||||
;
|
||||
; So 6502_C = !(Z80_C)
|
||||
;
|
||||
|
||||
; ld c,a
|
||||
!macro LD .dst, .reg {
|
||||
lda .reg
|
||||
sta .dst
|
||||
}
|
||||
|
||||
; ld c,80h
|
||||
!macro LD_REG_IMM .dst, .src {
|
||||
lda #.src
|
||||
sta .dst
|
||||
}
|
||||
|
||||
; ld ix,lf214
|
||||
; ld hl,0008h
|
||||
!macro LDW .dst, .const {
|
||||
lda #<.const ; LSB
|
||||
sta .dst
|
||||
lda #>.const ; MSB
|
||||
sta .dst + 1
|
||||
}
|
||||
|
||||
; ld a,(hl)
|
||||
!macro LD_REG_INDIRECT .dst, .reg16 {
|
||||
ldx #0
|
||||
lda (.reg16,x)
|
||||
sta .dst
|
||||
}
|
||||
|
||||
; ld (0f1fch),a
|
||||
!macro LD_INDIRECT_ABS .dst, .reg {
|
||||
lda .reg
|
||||
sta .dst
|
||||
}
|
||||
|
||||
; ld a,(0f1fdh)
|
||||
!macro LD_REG_INDIRECT_ABS .reg, .dst {
|
||||
lda .dst
|
||||
sta .reg
|
||||
}
|
||||
|
||||
; ld (ix+19h),a
|
||||
!macro LD_INDIRECT_OFFSET .reg16, .offset, .src {
|
||||
ldy #.offset
|
||||
lda .src
|
||||
sta (.reg16),y
|
||||
}
|
||||
|
||||
; ld (ix+19h),01h
|
||||
!macro LD_INDIRECT_OFFSET_IMM .reg16, .offset, .src {
|
||||
ldy #.offset
|
||||
lda #.src
|
||||
sta (.reg16),y
|
||||
}
|
||||
|
||||
; ld h,(ix+15h)
|
||||
!macro LD_REG_INDIRECT_OFFSET .dst, .reg16, .offset {
|
||||
ldy #.offset
|
||||
lda (.reg16),y
|
||||
sta .dst
|
||||
}
|
||||
|
||||
; ld (hl),a
|
||||
!macro LD_INDIRECT .reg16, .src {
|
||||
ldx #0
|
||||
lda .src
|
||||
sta (.reg16,x)
|
||||
}
|
||||
|
||||
; ld (hl),00h
|
||||
!macro LD_INDIRECT_IMM .reg16, .src {
|
||||
ldx #0
|
||||
lda #.src
|
||||
sta (.reg16,x)
|
||||
}
|
||||
|
||||
; ld hl,(0f1f6h)
|
||||
; ld (0f1f6h),hl
|
||||
!macro LDW_INDIRECT .dst, .src {
|
||||
lda .src
|
||||
sta .dst
|
||||
lda .src+1
|
||||
sta .dst+1
|
||||
}
|
||||
|
||||
; inc hl
|
||||
!macro INCW .reg16 {
|
||||
inc .reg16
|
||||
bne .j
|
||||
inc .reg16 + 1
|
||||
.j
|
||||
}
|
||||
|
||||
; inc (hl)
|
||||
!macro INC_INDIRECT .reg16 {
|
||||
ldx #0
|
||||
lda (.reg16,x)
|
||||
tay ; No inca for 6502! (65C02 only)
|
||||
iny
|
||||
tya
|
||||
sta (.reg16,x)
|
||||
}
|
||||
|
||||
; dec hl
|
||||
!macro DECW .reg16 {
|
||||
dec .reg16
|
||||
lda .reg16
|
||||
cmp #$ff
|
||||
bne .j
|
||||
dec .reg16 + 1
|
||||
.j
|
||||
}
|
||||
|
||||
; dec (ix+11h)
|
||||
!macro DEC_INDIRECT_OFFSET .reg, .offset {
|
||||
ldy #.offset
|
||||
lda (.reg),y
|
||||
tax ; No deca for 6502! (65C02 only)
|
||||
dex
|
||||
txa
|
||||
sta (.reg),y
|
||||
}
|
||||
|
||||
!macro JP_Z .label {
|
||||
bne .j
|
||||
jmp .label
|
||||
.j
|
||||
}
|
||||
|
||||
!macro JP_NZ .label {
|
||||
beq .j
|
||||
jmp .label
|
||||
.j
|
||||
}
|
||||
|
||||
!macro JP_C .label {
|
||||
bcs .j ; bcs, as C flag is inverted
|
||||
jmp .label
|
||||
.j
|
||||
}
|
||||
|
||||
!macro JP_NC .label {
|
||||
bcc .j ; bcc, as C flag is inverted
|
||||
jmp .label
|
||||
.j
|
||||
}
|
||||
|
||||
!macro RET_Z {
|
||||
bne .j
|
||||
rts
|
||||
.j
|
||||
}
|
||||
|
||||
!macro RET_NZ {
|
||||
beq .j
|
||||
rts
|
||||
.j
|
||||
}
|
||||
|
||||
!macro RET_C {
|
||||
bcs .j ; bcs, as C flag is inverted
|
||||
rts
|
||||
.j
|
||||
}
|
||||
|
||||
!macro RET_NC {
|
||||
bcc .j ; bcc, as C flag is inverted
|
||||
rts
|
||||
.j
|
||||
}
|
||||
|
||||
!macro PUSH16 .reg16 {
|
||||
lda .reg16
|
||||
pha
|
||||
lda .reg16+1
|
||||
pha
|
||||
}
|
||||
|
||||
!macro POP16 .reg16 {
|
||||
pla
|
||||
sta .reg16+1
|
||||
pla
|
||||
sta .reg16
|
||||
}
|
||||
|
||||
!macro ADDW .dst, .src {
|
||||
clc
|
||||
lda .dst
|
||||
adc .src
|
||||
sta .dst
|
||||
lda .dst+1
|
||||
adc .src+1
|
||||
sta .dst+1
|
||||
}
|
||||
|
||||
!macro INVERT_CARRY {
|
||||
php
|
||||
pla
|
||||
eor #$01 ; Invert C
|
||||
pha
|
||||
plp
|
||||
}
|
||||
|
||||
; Pre: Ensure that CARRY is setup correctly
|
||||
!macro SBCW .dst, .src {
|
||||
lda .dst
|
||||
sbc .src
|
||||
sta .dst
|
||||
lda .dst+1
|
||||
sbc .src+1
|
||||
sta .dst+1
|
||||
}
|
||||
|
||||
; sub (hl)
|
||||
!macro SUB_INDIRECT .reg16 {
|
||||
ldx #0
|
||||
sec
|
||||
sbc (.reg16,x)
|
||||
sta RegA
|
||||
}
|
||||
|
||||
; ldi
|
||||
; . (de++) <- (hl++)
|
||||
; . bc--
|
||||
!macro LDI {
|
||||
ldx #0
|
||||
lda (RegHL,x)
|
||||
sta (RegDE,x)
|
||||
inc RegL
|
||||
bne .a
|
||||
inc RegH
|
||||
.a
|
||||
inc RegE
|
||||
bne .b
|
||||
inc RegD
|
||||
.b
|
||||
dec RegBC
|
||||
bne .j
|
||||
dec RegBC+1
|
||||
.j
|
||||
}
|
||||
|
||||
; cp (ix+10h)
|
||||
!macro CP_INDIRECT_OFFSET .reg, .offset {
|
||||
ldy #.offset
|
||||
cmp (.reg),y
|
||||
}
|
43
Common/ZP-Macros.a
Normal file
43
Common/ZP-Macros.a
Normal file
@ -0,0 +1,43 @@
|
||||
RegA = $F0
|
||||
RegF = RegA+1 ; Not used
|
||||
RegBC = RegA+2 ; WORD
|
||||
RegC = RegA+2
|
||||
RegB = RegA+3
|
||||
RegDE = RegA+4 ; WORD
|
||||
RegE = RegA+4
|
||||
RegD = RegA+5
|
||||
RegHL = RegA+6 ; WORD
|
||||
RegL = RegA+6
|
||||
RegH = RegA+7
|
||||
RegIX = RegA+8 ; WORD
|
||||
|
||||
TmpHL = RegA+10
|
||||
TmpL = TmpHL
|
||||
TmpH = TmpHL+1
|
||||
|
||||
MBBase = TmpHL+2 ; Mockingboard base (only used in INIT - not in INTERRUPT)
|
||||
MBBaseL = MBBase
|
||||
MBBaseH = MBBase+1
|
||||
|
||||
ZPSize = MBBaseH - RegA + 1
|
||||
|
||||
;--------------------------------------
|
||||
|
||||
!macro SaveRegs .block {
|
||||
!set ZP = RegA
|
||||
!do while ZP <= TmpH {
|
||||
lda ZP
|
||||
sta .block + ZP - RegA
|
||||
!set ZP = ZP + 1
|
||||
}
|
||||
}
|
||||
|
||||
!macro RestoreRegs .block {
|
||||
!set ZP = RegA
|
||||
!do while ZP <= TmpH {
|
||||
lda .block + ZP - RegA
|
||||
sta ZP
|
||||
!set ZP = ZP + 1
|
||||
}
|
||||
}
|
||||
|
594
ConvertZ80/ConvertZ80.py
Normal file
594
ConvertZ80/ConvertZ80.py
Normal file
@ -0,0 +1,594 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
Z80Regs8 = ('a','b','c','d','e','f','h','l')
|
||||
Z80Regs16 = ('af', 'bc', 'de', 'hl', 'ix')
|
||||
|
||||
#==============================================================================
|
||||
|
||||
def GetLine(f):
|
||||
szLine = f.readline()
|
||||
while szLine != '':
|
||||
if szLine[0] != ';':
|
||||
return szLine
|
||||
szLine = f.readline()
|
||||
return ''
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def GetConst(S):
|
||||
const = S
|
||||
if re.match('\d', const): # 1st char is [0..9]
|
||||
if const[len(const)-1] == 'h':
|
||||
const = const[:len(const)-1] # Strip last char
|
||||
|
||||
if len(const) > 4 and const[0] == '0':
|
||||
const = const[1:] # Strip leading zero
|
||||
|
||||
if len(const) > 2 and const[0] == '0':
|
||||
const = const[1:] # Strip leading zero
|
||||
|
||||
const = '$' + const
|
||||
|
||||
return const
|
||||
|
||||
#--------------------------------------
|
||||
|
||||
# S = 0008h -> $0008
|
||||
# S = label -> label
|
||||
# S = labeh -> labeh
|
||||
def GetAddr16(S):
|
||||
return GetConst(S)
|
||||
|
||||
#--------------------------------------
|
||||
|
||||
# S = (0008h) -> $0008
|
||||
# S = (label) -> label
|
||||
# S = (labeh) -> labeh
|
||||
def GetIndirectAddr16(S):
|
||||
res = S[:len(S)-1] # Strip last char
|
||||
res = res[1:] # Strip 1st char
|
||||
return GetConst(res)
|
||||
|
||||
#--------------------------------------
|
||||
|
||||
def GetRegOffset(S):
|
||||
reg = S[1:3] # Middle 2 chars
|
||||
if reg not in Z80Regs16:
|
||||
print 'Illegal Z80 reg: ' + reg
|
||||
return ('', '')
|
||||
|
||||
offset = S[4:] # Strip 1st 4 chars: '(ix+'
|
||||
offset = offset[:len(offset)-1] # Strip last char: ')'
|
||||
|
||||
if offset[len(offset)-1] == 'h':
|
||||
offset = offset[:len(offset)-1] # Strip last char: 'h'
|
||||
offset = '$' + offset
|
||||
|
||||
return reg, offset
|
||||
|
||||
#==============================================================================
|
||||
|
||||
def adc(S):
|
||||
|
||||
if S[2] in Z80Regs8 and S[3] not in Z80Regs8:
|
||||
const = GetConst(S[3])
|
||||
print '\tlda\t' + 'Reg' + S[2].upper()
|
||||
print '\tadc\t' + '#' + const
|
||||
print '\tsta\t' + 'Reg' + S[2].upper()
|
||||
|
||||
else:
|
||||
print 'ADC error: unsupported addressing mode: ' + S[2], S[3]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def add(S):
|
||||
|
||||
ind2 = S[3][0] == '(' # S[3] is indirect
|
||||
|
||||
m2plus = re.search('\+', S[3])
|
||||
|
||||
if S[2] in Z80Regs8 and S[3] in Z80Regs8:
|
||||
# add a,a
|
||||
if S[2] == S[3]:
|
||||
print '\tlda\t' + 'Reg' + S[2].upper()
|
||||
print '\tasl\t'
|
||||
print '\tsta\t' + 'Reg' + S[2].upper()
|
||||
else:
|
||||
print '\tclc\t'
|
||||
print '\tlda\t' + 'Reg' + S[2].upper()
|
||||
print '\tadc\t' + 'Reg' + S[3].upper()
|
||||
print '\tsta\t' + 'Reg' + S[2].upper()
|
||||
|
||||
elif S[2] in Z80Regs8 and ind2 and m2plus:
|
||||
# add a,(ix+18h)
|
||||
reg, offset = GetRegOffset(S[3])
|
||||
print '\tclc\t' + '\t; CARRY possibly wrong'
|
||||
print '\tldy\t' + '#' + offset
|
||||
print '\tlda\t' + 'Reg' + S[2].upper()
|
||||
print '\tadc\t' + '(Reg' + reg.upper() + '),y'
|
||||
print '\tsta\t' + 'Reg' + S[2].upper()
|
||||
|
||||
elif S[2] in Z80Regs8:
|
||||
# add a,05h
|
||||
const = GetConst(S[3])
|
||||
print '\tclc\t' + '\t; CARRY possibly wrong'
|
||||
print '\tlda\t' + 'Reg' + S[2].upper()
|
||||
print '\tadc\t' + '#' + const
|
||||
print '\tsta\t' + 'Reg' + S[2].upper()
|
||||
|
||||
elif S[2] in Z80Regs16 and S[3] in Z80Regs16:
|
||||
# add hl,bc
|
||||
print '\t+ADDW\t' + 'Reg' + S[2].upper() + ', ' + 'Reg' + S[3].upper()
|
||||
|
||||
else:
|
||||
print 'ADD error: unsupported addressing mode: ' + S[2], S[3]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def _and(S):
|
||||
|
||||
ind2 = S[2][0] == '(' # S[2] is indirect
|
||||
|
||||
m2plus = re.search('\+', S[2])
|
||||
|
||||
if S[2] in Z80Regs8:
|
||||
# and e
|
||||
print '\tand\t' + 'Reg' + S[2].upper()
|
||||
|
||||
elif ind2 and m2plus:
|
||||
# and (ix+1bh)
|
||||
reg, offset = GetRegOffset(S[2])
|
||||
print '\tldy\t' + '#' + offset
|
||||
print '\tand\t' + '(Reg' + reg.upper() + '),y'
|
||||
|
||||
else:
|
||||
# and 3fh
|
||||
const = GetConst(S[2])
|
||||
print '\tand\t' + '#' + const
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def cp(S):
|
||||
|
||||
ind2 = S[2][0] == '(' # S[2] is indirect
|
||||
|
||||
m2plus = re.search('\+', S[2])
|
||||
|
||||
if ind2 and m2plus:
|
||||
# cp (ix+10h)
|
||||
reg, offset = GetRegOffset(S[2])
|
||||
print '\t+CP_INDIRECT_OFFSET\t' + 'Reg' + reg.upper() + ', ' + offset
|
||||
|
||||
elif not ind2:
|
||||
const = GetConst(S[2])
|
||||
print '\tcmp\t' + '#' + const
|
||||
|
||||
else:
|
||||
print 'CP error: unsupported addressing mode: ' + S[2]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def dec(S):
|
||||
|
||||
ind2 = S[2][0] == '(' # S[2] is indirect
|
||||
|
||||
m2plus = re.search('\+', S[2])
|
||||
|
||||
if S[2] in Z80Regs8:
|
||||
print '\tdec\t' + 'Reg' + S[2].upper()
|
||||
|
||||
elif S[2] in Z80Regs16:
|
||||
# dec hl
|
||||
reg = GetAddr16(S[2])
|
||||
print '\t+DECW\t' + 'Reg' + reg.upper()
|
||||
|
||||
elif ind2 and m2plus:
|
||||
# dec (ix+11h)
|
||||
reg, offset = GetRegOffset(S[2])
|
||||
if reg == '':
|
||||
return
|
||||
print '\t+DEC_INDIRECT_OFFSET\t' + 'Reg' + reg.upper() + ', ' + offset
|
||||
|
||||
else:
|
||||
print ';DEC error: unsupported addressing mode: ' + S[2]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def inc(S):
|
||||
|
||||
ind2 = S[2][0] == '(' # S[2] is indirect
|
||||
|
||||
if S[2] in Z80Regs8:
|
||||
print '\tinc\t' + 'Reg' + S[2].upper()
|
||||
return
|
||||
|
||||
#
|
||||
|
||||
if ind2:
|
||||
# inc (hl)
|
||||
reg = GetIndirectAddr16(S[2])
|
||||
|
||||
else:
|
||||
# inc hl
|
||||
reg = GetAddr16(S[2])
|
||||
|
||||
if reg not in Z80Regs16:
|
||||
print 'INC error: Illegal Z80 reg: ' + reg
|
||||
elif ind2:
|
||||
print '\t+INC_INDIRECT\t' + 'Reg' + reg.upper()
|
||||
else:
|
||||
print '\t+INCW\t' + 'Reg' + reg.upper()
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def jp(S):
|
||||
|
||||
if S[3] == '':
|
||||
print '\tjmp\t' + S[2]
|
||||
return
|
||||
|
||||
if S[2] == 'z':
|
||||
print '\t+JP_Z\t' + S[3]
|
||||
elif S[2] == 'nz':
|
||||
print '\t+JP_NZ\t' + S[3]
|
||||
elif S[2] == 'c':
|
||||
print '\t+JP_C\t' + S[3]
|
||||
elif S[2] == 'nc':
|
||||
print '\t+JP_NC\t' + S[3]
|
||||
else:
|
||||
print ';JP error: unsupported cc: ' + S[2]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def jr(S):
|
||||
|
||||
if S[3] == '':
|
||||
print '\tjmp\t' + S[2]
|
||||
return
|
||||
|
||||
if S[2] == 'z':
|
||||
print '\tbeq\t' + S[3]
|
||||
elif S[2] == 'nz':
|
||||
print '\tbne\t' + S[3]
|
||||
elif S[2] == 'c':
|
||||
print '\tbcc\t' + S[3] # C inverted
|
||||
elif S[2] == 'nc':
|
||||
print '\tbcs\t' + S[3] # C inverted
|
||||
else:
|
||||
print 'JR error: unsupported cc: ' + S[2]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def ld(S):
|
||||
|
||||
m2 = S[2] in Z80Regs8
|
||||
m3 = S[3] in Z80Regs8
|
||||
|
||||
m2plus = re.search('\+', S[2])
|
||||
m3plus = re.search('\+', S[3])
|
||||
|
||||
len2 = len(S[2])
|
||||
len3 = len(S[3])
|
||||
|
||||
ind2 = S[2][0] == '(' # S[2] is indirect
|
||||
ind3 = S[3][0] == '(' # S[3] is indirect
|
||||
|
||||
if m2 and m3:
|
||||
# ld c,a
|
||||
print '\t+LD\t' + 'Reg' + S[2].upper() + ', ' + 'Reg' + S[3].upper()
|
||||
return
|
||||
|
||||
elif m2 and not ind3:
|
||||
# ld c,80h
|
||||
const = GetConst(S[3])
|
||||
print '\t+LD_REG_IMM\t' + 'Reg' + S[2].upper() + ', ' + const
|
||||
return
|
||||
|
||||
elif m2 and ind3 and len3 == len('(xx)'):
|
||||
# ld a,(hl)
|
||||
reg = S[3][1:3] # Middle 2 chars
|
||||
if reg not in Z80Regs16:
|
||||
print 'Illegal Z80 reg: ' + reg
|
||||
return
|
||||
print '\t+LD_REG_INDIRECT\t' + 'Reg' + S[2].upper() + ', ' + 'Reg' + reg.upper()
|
||||
return
|
||||
|
||||
elif m2 and ind3 and m3plus:
|
||||
# ld h,(ix+15h)
|
||||
reg, offset = GetRegOffset(S[3])
|
||||
if reg == '':
|
||||
return
|
||||
print '\t+LD_REG_INDIRECT_OFFSET\t' + 'Reg' + S[2].upper() + ', ' + 'Reg' + reg.upper() + ', ' + offset
|
||||
return
|
||||
|
||||
elif m2 and ind3:
|
||||
# ld a,(0f1fdh)
|
||||
# ld a,(lf1fd)
|
||||
abs = GetIndirectAddr16(S[3])
|
||||
print '\t+LD_REG_INDIRECT_ABS\t' + 'Reg' + S[2].upper() + ', ' + abs
|
||||
return
|
||||
|
||||
elif S[2] in Z80Regs16 and ind3:
|
||||
# ld hl,(lf1f6)
|
||||
# ld hl,(0f1f6h)
|
||||
src = GetIndirectAddr16(S[3])
|
||||
print '\t+LDW_INDIRECT\t' + 'Reg' + S[2].upper() + ', ' + src
|
||||
return
|
||||
|
||||
elif S[2] in Z80Regs16:
|
||||
# ld ix,lf214
|
||||
# ld hl,0008h
|
||||
const = GetAddr16(S[3])
|
||||
print '\t+LDW\t' + 'Reg' + S[2].upper() + ', ' + const
|
||||
return
|
||||
|
||||
elif ind2 and m2plus and m3:
|
||||
# ld (ix+19h),a
|
||||
reg, offset = GetRegOffset(S[2])
|
||||
if reg == '':
|
||||
return
|
||||
print '\t+LD_INDIRECT_OFFSET\t' + 'Reg' + reg.upper() + ', ' + offset + ', ' + 'Reg' + S[3].upper()
|
||||
return
|
||||
|
||||
elif ind2 and m2plus and not m3:
|
||||
# ld (ix+19h),01h
|
||||
reg, offset = GetRegOffset(S[2])
|
||||
if reg == '':
|
||||
return
|
||||
const = GetConst(S[3])
|
||||
print '\t+LD_INDIRECT_OFFSET_IMM\t' + 'Reg' + reg.upper() + ', ' + offset + ', ' + const
|
||||
return
|
||||
|
||||
elif ind2 and m3:
|
||||
# ld (hl),a
|
||||
# ld (0f1fch),a
|
||||
# ld (lf1fc),a
|
||||
Addr16 = GetIndirectAddr16(S[2])
|
||||
if Addr16 in Z80Regs16:
|
||||
print '\t+LD_INDIRECT\t' + 'Reg' + Addr16.upper() + ', ' + 'Reg' + S[3].upper()
|
||||
else:
|
||||
print '\t+LD_INDIRECT_ABS\t' + Addr16 + ', ' + 'Reg' + S[3].upper()
|
||||
return
|
||||
|
||||
elif ind2 and not m3:
|
||||
# ld (hl),00h
|
||||
# ld (0f1f6h),hl
|
||||
# ld (lf1f6h),hl
|
||||
Addr16 = GetIndirectAddr16(S[2])
|
||||
const = GetConst(S[3])
|
||||
if Addr16 in Z80Regs16:
|
||||
print '\t+LD_INDIRECT_IMM\t' + 'Reg' + Addr16.upper() + ', ' + const
|
||||
elif const in Z80Regs16:
|
||||
print '\t+LDW_INDIRECT\t' + Addr16 + ', ' + 'Reg' + const.upper()
|
||||
else:
|
||||
print 'Illegal Z80 reg: ' + Addr16
|
||||
return
|
||||
|
||||
#
|
||||
|
||||
print 'LD error: No match for ' + S[2], S[3]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def orr(S):
|
||||
|
||||
if S[2] in Z80Regs8:
|
||||
# or l
|
||||
print '\tora\t' + 'Reg' + S[2].upper()
|
||||
else:
|
||||
# or 38h
|
||||
const = GetConst(S[2])
|
||||
print '\tora\t' + '#' + const
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def pop(S):
|
||||
|
||||
if S[2] in Z80Regs16:
|
||||
# pop de
|
||||
print '\t+POP16\t' + 'Reg' + S[2].upper()
|
||||
else:
|
||||
print 'POP error: unsupported addressing mode'
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def push(S):
|
||||
|
||||
if S[2] in Z80Regs16:
|
||||
# push de
|
||||
print '\t+PUSH16\t' + 'Reg' + S[2].upper()
|
||||
else:
|
||||
print 'PUSH error: unsupported addressing mode'
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def sbc(S):
|
||||
|
||||
if S[2] in Z80Regs16 and S[3] in Z80Regs16:
|
||||
# sbc hl,bc
|
||||
print '\t+SBCW\t' + 'Reg' + S[2].upper() + ', ' + 'Reg' + S[3].upper()
|
||||
else:
|
||||
print 'SBC error: unsupported addressing mode'
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def sub(S):
|
||||
|
||||
ind2 = S[2][0] == '(' # S[2] is indirect
|
||||
|
||||
if S[2] in Z80Regs8:
|
||||
# sub l
|
||||
print '\tsbc\t' + 'Reg' + S[2].upper() + '\t; CARRY possibly wrong'
|
||||
|
||||
elif ind2:
|
||||
# sub (hl)
|
||||
reg = GetIndirectAddr16(S[2])
|
||||
if reg not in Z80Regs16:
|
||||
print 'DEC error: Illegal Z80 reg: ' + Addr16
|
||||
return
|
||||
print '\t+SUB_INDIRECT\t' + 'Reg' + reg.upper()
|
||||
|
||||
else:
|
||||
# sub 80h
|
||||
const = GetConst(S[2])
|
||||
print '\tsec\t' + '\t; CARRY possibly wrong'
|
||||
print '\tsbc\t' + '#' + const
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def ret(S):
|
||||
|
||||
if S[2] == '':
|
||||
print '\trts'
|
||||
elif S[2] == 'z':
|
||||
print '\t+RET_Z\t' + S[3]
|
||||
elif S[2] == 'nz':
|
||||
print '\t+RET_NZ\t' + S[3]
|
||||
elif S[2] == 'c':
|
||||
print '\t+RET_C\t' + S[3]
|
||||
elif S[2] == 'nc':
|
||||
print '\t+RET_NC\t' + S[3]
|
||||
else:
|
||||
print ';RET error: unsupported cc: ' + S[2]
|
||||
|
||||
print ''
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def xor(S):
|
||||
|
||||
ind2 = S[2][0] == '(' # S[2] is indirect
|
||||
|
||||
if S[2] in Z80Regs8:
|
||||
print '\t+LD_REG_IMM\t' + 'Reg' + S[2].upper() + ', 0' + '\t; xor ' + S[2]
|
||||
# elif ind2:
|
||||
# reg = GetIndirectAddr16(S[2])
|
||||
else:
|
||||
print 'XOR error: unsupported addressing mode'
|
||||
|
||||
#==============================================================================
|
||||
|
||||
def Process(S):
|
||||
if S[0] != '':
|
||||
print S[0]
|
||||
|
||||
if S[1] == '':
|
||||
return 1 # No opcode
|
||||
elif S[1] == 'nop':
|
||||
return 0 # Assume this is data section
|
||||
|
||||
elif S[1] == 'adc':
|
||||
adc(S)
|
||||
elif S[1] == 'add':
|
||||
add(S)
|
||||
elif S[1] == 'and':
|
||||
_and(S)
|
||||
elif S[1] == 'call':
|
||||
print '\tjsr\t' + S[2]
|
||||
elif S[1] == 'dec':
|
||||
dec(S)
|
||||
elif S[1] == 'cp':
|
||||
cp(S)
|
||||
elif S[1] == 'inc':
|
||||
inc(S)
|
||||
elif S[1] == 'jp':
|
||||
jp(S)
|
||||
elif S[1] == 'jr':
|
||||
jr(S)
|
||||
elif S[1] == 'ld':
|
||||
ld(S)
|
||||
elif S[1] == 'ldi':
|
||||
print '\t+LDI'
|
||||
elif S[1] == 'or':
|
||||
orr(S)
|
||||
elif S[1] == 'pop':
|
||||
pop(S)
|
||||
elif S[1] == 'push':
|
||||
push(S)
|
||||
elif S[1] == 'ret':
|
||||
ret(S)
|
||||
elif S[1] == 'sbc':
|
||||
sbc(S)
|
||||
elif S[1] == 'sub':
|
||||
sub(S)
|
||||
elif S[1] == 'xor':
|
||||
xor(S)
|
||||
else:
|
||||
s = ';\t'
|
||||
for i in range(len(S)):
|
||||
s = s + S[i]
|
||||
s = s + '\t; ** Unknown opcode **'
|
||||
print s
|
||||
|
||||
return 1
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def hdr_code():
|
||||
print ';ACME 0.85'
|
||||
print ''
|
||||
print '!cpu 6502 ; Compatible with all Apple2\'s'
|
||||
print '!to \"TEST\", plain'
|
||||
print '!sl \"TEST.labels\"'
|
||||
print '*=$6000'
|
||||
print ''
|
||||
print '!source \"..\\Common\\Z80-Macros.a\"'
|
||||
print '!source \"..\\Common\\ZP-Macros.a\"'
|
||||
print '!source \"..\\Common\\AppleDefs.a\"'
|
||||
print '!source \"..\\Common\\MockingboardDefs.a\"'
|
||||
print ''
|
||||
print ';------------------------------------------------------------------------------'
|
||||
print ''
|
||||
print '!zone code'
|
||||
print ''
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def hdr_data():
|
||||
print ''
|
||||
print ';------------------------------------------------------------------------------'
|
||||
print ''
|
||||
print '!zone data'
|
||||
print ''
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def help():
|
||||
print 'ConvertZ80 v1.0.0'
|
||||
print ''
|
||||
print 'Usage: ConvertZ80.py <z80.asm>'
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
help()
|
||||
return
|
||||
|
||||
hFileIn = open(sys.argv[1], 'r')
|
||||
|
||||
#if len(sys.argv) >= 3:
|
||||
# hFileOut = open(sys.argv[2], 'w')
|
||||
|
||||
hdr_code()
|
||||
|
||||
n = 0
|
||||
while n < 1000:
|
||||
szLine = GetLine(hFileIn)
|
||||
if szLine == '':
|
||||
break
|
||||
Split = re.split('\s+|,', szLine)
|
||||
if Process(Split) == 0:
|
||||
break
|
||||
n = n + 1
|
||||
|
||||
hdr_data()
|
||||
|
||||
hFileIn.close()
|
||||
#hFileOut.close()
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
main()
|
1450
Cybernoid/Cybernoid.a
Normal file
1450
Cybernoid/Cybernoid.a
Normal file
File diff suppressed because it is too large
Load Diff
4
Cybernoid/build.bat
Normal file
4
Cybernoid/build.bat
Normal file
@ -0,0 +1,4 @@
|
||||
D:\Apple][\acme085\acme.exe cybernoid.a
|
||||
D:\Apple][\InsertBIN2AWS\debug\InsertBIN2AWS.exe cybernoid 6000 cybernoid.aws
|
||||
java -jar "D:\Apple][\Apple Commander\ac\AppleCommander-1.3.3.9-ac.jar" -d cybernoid ..\ReleaseDSK\Cybernoid.dsk
|
||||
cat cybernoid | java -jar "D:\Apple][\Apple Commander\ac\AppleCommander-1.3.3.9-ac.jar" -p Cybernoid bin 24576 ..\ReleaseDSK\Cybernoid.dsk
|
1261
Cybernoid2/Cybernoid2.a
Normal file
1261
Cybernoid2/Cybernoid2.a
Normal file
File diff suppressed because it is too large
Load Diff
4
Cybernoid2/build.bat
Normal file
4
Cybernoid2/build.bat
Normal file
@ -0,0 +1,4 @@
|
||||
D:\Apple][\acme085\acme.exe cybernoid2.a
|
||||
D:\Apple][\InsertBIN2AWS\debug\InsertBIN2AWS.exe cybernoid2 6000 cybernoid2.aws
|
||||
java -jar "D:\Apple][\Apple Commander\ac\AppleCommander-1.3.3.9-ac.jar" -d cybernoid2 ..\ReleaseDSK\Cybernoid.dsk
|
||||
cat cybernoid2 | java -jar "D:\Apple][\Apple Commander\ac\AppleCommander-1.3.3.9-ac.jar" -p Cybernoid2 bin 24576 ..\ReleaseDSK\Cybernoid.dsk
|
45
ReleaseDSK/Cybernoid-relnote.txt
Normal file
45
ReleaseDSK/Cybernoid-relnote.txt
Normal file
@ -0,0 +1,45 @@
|
||||
My motivation was to really push the MAME AY8910 emu code, as the Apple
|
||||
Mockingboard music (Skyfox, Ultima) wasn't really exercising it that
|
||||
hard.
|
||||
|
||||
So as a little R&D proj, I thought I'd convert Dave Rogers' Spectrum
|
||||
128 Cybernoid routine (written in 1988).
|
||||
|
||||
Here's a summary of how I did it:
|
||||
. I got cybernoid.ay from
|
||||
http://www.worldofspectrum.org/projectay/gdmusic.htm
|
||||
. Split it into bin's with AYSplitR
|
||||
. Disassembled with Inkland's dz80w (www.inkland.org)
|
||||
. I wrote 6502 macros to replace the z80 opcodes
|
||||
. For cybernoid, I hand converted the z80 code to 6502 (using the
|
||||
macros)
|
||||
. I added a few extension to AppleWin's debugger to help debug the 6502
|
||||
code (ACME symbol loading & ZP pointer support).
|
||||
|
||||
I use Skyfox's MB detection routine.
|
||||
|
||||
The Z80 regs are emulated with zero-page memory locations $F0..$F8
|
||||
The playback routine is very inefficient, as it:
|
||||
. saves the ZP memory
|
||||
. restores the Z80 regs
|
||||
. runs the IRQ handler
|
||||
. saves the Z80 regs
|
||||
. restores the ZP memory
|
||||
|
||||
This allows playback to work simultaneously with Applesoft & ProDOS. If
|
||||
DOS3.3 doesn't disable IRQs around disk I/O, then it won't work on a
|
||||
real Apple (under DOS3.3), but it'll still work on an emulator :-)
|
||||
|
||||
I profiled the IRQ handler and IIRC, it takes about 20% of the frame on
|
||||
average. This is poor, but the code can easily be optimised. Remember
|
||||
this was really just a proof of concept.
|
||||
|
||||
After this, I wrote a python script to do the Z80->6502, and quickly
|
||||
converted Cybernoid-II.
|
||||
|
||||
Currently playback on real h/w produces noisy renditions of the tunes. I
|
||||
have replaced my AY-register update routine with the slower one used by Skyfox
|
||||
which gives better but not perfect results.
|
||||
|
||||
Tom
|
||||
25 March 2006
|
6
ReleaseDSK/Versions.txt
Normal file
6
ReleaseDSK/Versions.txt
Normal file
@ -0,0 +1,6 @@
|
||||
v5: 02/04/2006 - Z80 Emu: Fixed SBCW bug that affected portamento
|
||||
UI: Added timer (M:S:F) & control over enable & volume
|
||||
v4: 18/03/2006 - Disable Timer1 at INIT entrypoint
|
||||
v3: 04/03/2006 - Use Skyfox's routine to update AY regs
|
||||
v2: 21/02/2006 - Spectrum stereo (L=A+B/2, R=C'+B'/2)
|
||||
v1: 13/02/2006 - Dual mono (L=A+B+C, R=A'+B'+C')
|
Loading…
x
Reference in New Issue
Block a user