Made DSPTool more informative and actually fail when compile fails (right now it kept creating invalid files)

Also, created an example test which uses the INCLUDE directive. Tests are much shorter and human-readable now!

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3064 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
XTra.KrazzY 2009-04-24 15:31:13 +00:00
parent 92e6d7c283
commit e0a202b7ef
4 changed files with 388 additions and 3 deletions

View File

@ -35,8 +35,10 @@ bool Assemble(const char *text, std::vector<u16> *code)
// TODO: fix the terrible api of the assembler.
DSPAssembler assembler(settings);
if (!assembler.Assemble(text, code))
if (!assembler.Assemble(text, code)) {
printf("%s", assembler.GetErrorString().c_str());
return false;
}
return true;
}

View File

@ -0,0 +1,356 @@
; This is the trojan program we send to the DSP from DSPSpy to figure it out.
REGS_BASE: equ 0x0f80
MEM_HI: equ 0x0f7E
MEM_LO: equ 0x0f7F
;
; CODE STARTS HERE.
; Interrupt vectors 8 vectors, 2 opcodes each
jmp irq0
jmp irq1
jmp irq2
jmp irq3
jmp irq4
jmp irq5
jmp irq6
jmp irq7
; Main code at 0x10
sbset #0x02
sbset #0x03
sbclr #0x04
sbset #0x05
sbset #0x06
set16
lri $CR, #0x00ff
; Why do we have a main label here?
main:
clr $ACC1
clr $ACC0
; get address of memory dump and copy it to DRAM
call wait_for_dsp_mbox
si @DMBH, #0x8888
si @DMBL, #0xdead
si @DIRQ, #0x0001
call wait_for_cpu_mbox
lrs $AC0.M, @CMBL
andi $ac1.m, #0x7fff
sr @MEM_HI, $AC1.M
sr @MEM_LO, $AC0.M
lri $ax0.l, #0
lri $ax1.l, #0 ;(DSP_CR_IMEM | DSP_CR_TO_CPU)
lri $ax0.h, #0x2000
lr $ac0.l, @MEM_HI
lr $ac0.m, @MEM_LO
call do_dma
; get address of registers and DMA them to ram
call wait_for_dsp_mbox
si @DMBH, #0x8888
si @DMBL, #0xbeef
si @DIRQ, #0x0001
call wait_for_cpu_mbox
lrs $AC0.M, @CMBL
andi $ac1.m, #0x7fff
sr @MEM_HI, $AC1.M
sr @MEM_LO, $AC0.M
lri $ax0.l, #REGS_BASE
lri $ax1.l, #0 ;(DSP_CR_IMEM | DSP_CR_TO_CPU)
lri $ax0.h, #0x80
lr $ac0.l, @MEM_HI
lr $ac0.m, @MEM_LO
call do_dma
; Read in all the registers from RAM
lri $ar0, #REGS_BASE+1
lrri $ar1, @$ar0
lrri $ar2, @$ar0
lrri $ar3, @$ar0
lrri $ix0, @$ar0
lrri $ix1, @$ar0
lrri $ix2, @$ar0
lrri $ix3, @$ar0
lrri $r08, @$ar0
lrri $r09, @$ar0
lrri $r10, @$ar0
lrri $r11, @$ar0
lrri $st0, @$ar0
lrri $st1, @$ar0
lrri $st2, @$ar0
lrri $st3, @$ar0
lrri $ac0.h, @$ar0
lrri $ac1.h, @$ar0
lrri $cr, @$ar0
lrri $sr, @$ar0
lrri $prod.l, @$ar0
lrri $prod.m1, @$ar0
lrri $prod.h, @$ar0
lrri $prod.m2, @$ar0
lrri $ax0.l, @$ar0
lrri $ax1.l, @$ar0
lrri $ax0.h, @$ar0
lrri $ax1.h, @$ar0
lrri $ac0.l, @$ar0
lrri $ac1.l, @$ar0
lrri $ac0.m, @$ar0
lrri $ac1.m, @$ar0
lr $ar0, @REGS_BASE
jmp start_of_test
; This is where we jump when we're done testing, see above.
end_of_test:
nop
nop
nop
nop
nop
nop
nop
; We just fall into a loop, playing dead until someone resets the DSP.
dead_loop:
jmp dead_loop
; Utility function to do DMA.
; ac0.l:ac0.m - external address.
; ax0.l - address in DSP
do_dma:
sr @DSMAH, $ac0.l
sr @DSMAL, $ac0.m
sr @DSPA, $ax0.l
sr @DSCR, $ax1.l
sr @DSBL, $ax0.h ; This kicks off the DMA.
; Waits for said DMA to complete by watching a bit in DSCR.
wait_dma:
LRS $AC1.M, @DSCR
andcf $ac1.m, #0x0004
JLZ wait_dma
RET
; This waits for a mail to arrive in the DSP in-mailbox.
wait_for_dsp_mbox:
lrs $AC1.M, @DMBH
andcf $ac1.m, #0x8000
jlz wait_for_dsp_mbox
ret
; This waits for the CPU to grab a mail that we just sent from the DSP.
wait_for_cpu_mbox:
lrs $AC1.M, @cmbh
andcf $ac1.m, #0x8000
jlnz wait_for_cpu_mbox
ret
; IRQ handlers. Not entirely sure what good they do currently.
irq0:
lri $ac0.m, #0x0000
jmp irq
irq1:
lri $ac0.m, #0x0001
jmp irq
irq2:
lri $ac0.m, #0x0002
jmp irq
irq3:
lri $ac0.m, #0x0003
jmp irq
irq4:
lri $ac0.m, #0x0004
jmp irq
irq5:
; No idea what this code is doing.
set16
mrr $st1, $ac0.l
mrr $st1, $ac0.m
clr $acc0
mrr $ac0.m, $st1
mrr $ac0.l, $st1
nop ; Or why there's a nop sled here.
nop
nop
nop
nop
nop
rti
lri $ac0.m, #0x0005
jmp irq
irq6:
lri $ac0.m, #0x0006
jmp irq
irq7:
lri $ac0.m, #0x0007
jmp irq
irq:
lrs $AC1.M, @DMBH
andcf $ac1.m, #0x8000
jlz irq
si @DMBH, #0x8BAD
sr @DMBL, $r11
;sr @DMBL, $ac0.m
si @DIRQ, #0x0001
halt
; DMA:s the current state of the registers back to the PowerPC. To do this,
; it must write the contents of all regs to DRAM.
send_back:
; make state safe.
set16
; store registers to reg table
sr @REGS_BASE, $ar0
lri $ar0, #(REGS_BASE + 1)
srri @$ar0, $ar1
srri @$ar0, $ar2
srri @$ar0, $ar3
srri @$ar0, $ix0
srri @$ar0, $ix1
srri @$ar0, $ix2
srri @$ar0, $ix3
srri @$ar0, $r08
srri @$ar0, $r09
srri @$ar0, $r10
srri @$ar0, $r11
srri @$ar0, $st0
srri @$ar0, $st1
srri @$ar0, $st2
srri @$ar0, $st3
srri @$ar0, $ac0.h
srri @$ar0, $ac1.h
srri @$ar0, $cr
srri @$ar0, $sr
srri @$ar0, $prod.l
srri @$ar0, $prod.m1
srri @$ar0, $prod.h
srri @$ar0, $prod.m2
srri @$ar0, $ax0.l
srri @$ar0, $ax1.l
srri @$ar0, $ax0.h
srri @$ar0, $ax1.h
srri @$ar0, $ac0.l
srri @$ar0, $ac1.l
srri @$ar0, $ac0.m
srri @$ar0, $ac1.m
; Regs are stored. Prepare DMA.
lri $ax0.l, #0x0000
lri $ax1.l, #1 ;(DSP_CR_IMEM | DSP_CR_TO_CPU)
lri $ax0.h, #0x200
lr $ac0.l, @MEM_HI
lr $ac0.m, @MEM_LO
lri $ar1, #8+8
; Now, why are we looping here?
bloop $ar1, dma_copy
call do_dma
addi $ac0.m, #0x200
mrr $ac1.m, $ax0.l
addi $ac1.m, #0x100
mrr $ax0.l, $ac1.m
nop
dma_copy:
nop
; Wait for the CPU to send us a mail.
call wait_for_dsp_mbox
si @DMBH, #0x8888
si @DMBL, #0xfeeb
si @DIRQ, #0x0001
; wait for the CPU to recieve our response before we execute the next op
call wait_for_cpu_mbox
lrs $AC0.M, @CMBL
andi $ac1.m, #0x7fff
; Restore all regs again so we're ready to execute another op.
lri $ar0, #REGS_BASE+1
lrri $ar1, @$ar0
lrri $ar2, @$ar0
lrri $ar3, @$ar0
lrri $ix0, @$ar0
lrri $ix1, @$ar0
lrri $ix2, @$ar0
lrri $ix3, @$ar0
lrri $r08, @$ar0
lrri $r09, @$ar0
lrri $r10, @$ar0
lrri $r11, @$ar0
lrri $st0, @$ar0
lrri $st1, @$ar0
lrri $st2, @$ar0
lrri $st3, @$ar0
lrri $ac0.h, @$ar0
lrri $ac1.h, @$ar0
lrri $cr, @$ar0
lrri $sr, @$ar0
lrri $prod.l, @$ar0
lrri $prod.m1, @$ar0
lrri $prod.h, @$ar0
lrri $prod.m2, @$ar0
lrri $ax0.l, @$ar0
lrri $ax1.l, @$ar0
lrri $ax0.h, @$ar0
lrri $ax1.h, @$ar0
lrri $ac0.l, @$ar0
lrri $ac1.l, @$ar0
lrri $ac0.m, @$ar0
lrri $ac1.m, @$ar0
lr $ar0, @REGS_BASE
ret ; from send_back
; If you are in set40 mode, use this instead of send_back if you want to stay
; in set40 mode.
send_back_40:
set16
call send_back
set40
ret
; This one's odd. Doesn't look like it should work since it uses ac0.m but
; increments acm0... (acc0)
dump_memory:
lri $ar2, #0x0000
lri $ac0.m, #0x1000
lri $ar1, #0x1000
bloop $ar1, _fill_loop2
mrr $ar3, $ac0.m
nx'ld : $AX0.H, $AX1.H, @$AR0
mrr $ac1.m, $ar0
mrr $ar0, $ar2
srri @$ar0, $ax1.h
mrr $ar2, $ar0
mrr $ar0, $ac1.m
addis $acc0, #0x1
_fill_loop2:
nop
ret ; from dump_memory
start_of_test:

View File

@ -0,0 +1,20 @@
include "dsp_base.inc"
; Right here we are at a specific predetermined state.
; Ideal environment to try instructions.
; We can call send_back at any time to send data back to the PowerPC.
; Calling set40 here seemed to crash the dsp tester in strange ways
; until I added set16 in send_back. Seems clear that it affects something important.
lri $AC0.M, #0x1000
call send_back
set40
lri $AC0.M, #0x1000
set16
call send_back
; We're done, DO NOT DELETE THIS LINE
jmp end_of_test

View File

@ -210,7 +210,8 @@ int main(int argc, const char *argv[])
{
if(argc == 1 || (argc == 2 && (!strcmp(argv[1], "--help") || (!strcmp(argv[1], "-?")))))
{
printf("USAGE: DSPTool [-d] [-o <FILE>] [-h <FILE>] <DSP ASSEMBLER FILE>\n");
printf("USAGE: DSPTool [-?] [--help] [-d] [-o <FILE>] [-h <FILE>] <DSP ASSEMBLER FILE>\n");
printf("-? / --help: Prints this message\n");
printf("-d: Disassemble\n");
printf("-o <OUTPUT FILE>: Results from stdout redirected to a file\n");
printf("-h <HEADER FILE>: Output assembly results to a header\n");
@ -292,7 +293,10 @@ int main(int argc, const char *argv[])
if (File::ReadFileToString(true, input_name.c_str(), &source))
{
std::vector<u16> code;
Assemble(source.c_str(), &code);
if(!Assemble(source.c_str(), &code)) {
printf("Assemble: Assembly failed due to errors\n");
return 1;
}
if (!output_name.empty())
{
std::string binary_code;
@ -307,5 +311,8 @@ int main(int argc, const char *argv[])
}
}
}
printf("Assembly completed successfully!\n");
return 0;
}