Commit of v5 code

This commit is contained in:
tomcw 2017-04-21 21:56:00 +01:00
commit 84ff354f52
13 changed files with 4166 additions and 0 deletions

13
Common/AppleDefs.a Normal file
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

4
Cybernoid/build.bat Normal file
View 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

File diff suppressed because it is too large Load Diff

4
Cybernoid2/build.bat Normal file
View 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

1
README.md Normal file
View File

@ -0,0 +1 @@
# Cybernoid

View 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
View 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')