O DEPURADOR¶
Introdução¶
O MAME inclui um depurador interativo de baixo nível que tem como alvo o sistema de emulação. Pode ser uma ferramenta útil para diagnosticar problemas relacionados à emulação, no desenvolvimento do software para rodar em sistemas antigos, na criação das trapaças, para o "hacking" de uma ROM ou simplesmente para investigar como o software funciona.
Use a opção -debug
na linha de comando para iniciar o MAME com o
depurador ativado. Como padrão, pressione a tecla ' (")
durante a emulação para entrar no depurador (é possível alterar a tecla
alterando a configuração Entra no depurador).
A aparência exata do depurador depende do seu sistema operacional e das opções com as quais o MAME foi compilado. Todas as variantes do depurador fornecem uma interface com várias janelas para a visualização do conteúdo da memória e do código desmontado.
A janela do console do depurador é uma janela especial que mostra o conteúdo dos registros da CPU, o código desmontado em torno do endereço do contador atual do programa e fornece também uma interface com linha de comando que auxilia em toda a funcionalidade do depurador.
Os comandos do depurador¶
Os comandos do depurador são descritos nas seções abaixo. Também é
possível digitar help comando
no console do depurador para que a
ajuda seja exibida diretamente na tela do depurador.
- Comandos gerais do depurador
- Comandos para a depuração da memória
- Comandos de execução do depurador
- Comandos do ponto de interrupção do depurador
- Comandos do ponto de controle do depurador
- Comandos do ponto de identificação
- Comandos de depuração do ponto de exceção
- Comandos da anotação do código do depurador
- Comandos para depuração de trapaça
- Comandos para a depuração de imagens
Determinando os dispositivos e as faixas de endereço¶
Os diversos comandos de depuração aceitam parâmetros que determinam em qual dispositivo se vai operar. Caso um dispositivo não seja definido de forma explícita, a CPU que será utilizada é a que estiver visível no momento. Os dispositivos podem ser definidos através de uma etiqueta ou através do número da CPU no depurador:
As etiquetas são os caminhos separados por dois pontos (
:
) que o MAME utiliza para identificar os dispositivos dentro de um sistema (:maincpu
por exemplo). Você os vê nas opções de configuração dos dispositivos de slot, nas listas de origem da desmontagem do depurador, no visualizador da memória e em vários outros lugares dentro da interface do MAME.A numeração da CPU é um incremento monotônico dos números que o depurador atribui aos dispositivos do tipo CPU dentro de um sistema, começando por zero. O símbolo
cpunum
contém o número da CPU que estiver visível no momento (você pode vê-la usando o comandoprint cpunum
no console).
Quando uma etiqueta é iniciada com um circunflexo ^
ou ponto
.
, ela é interpretada com relação a CPU que estiver visível no momento, caso contrário,
ela é interpretada com relação ao dispositivo raiz do sistema. Quando um
argumento do dispositivo for ambíguo como uma etiqueta ou um número da
CPU, ele será interpretado como uma etiqueta.
Exemplos:
maincpu
:maincpu
.^melodypsg
melodypsg
..:adc
adc
.2
Os comandos que operam na memória estendem isso ao permitir que a
etiqueta do dispositivo ou o número da CPU seja opcionalmente seguido
por um identificador na região do endereçamento, ele são cadeias de
caracteres do tipo etiqueta. Você pode vê-los nas listas de origem do
visualizador da memória do depurador. Quando o identificador da região
do endereçamento for omitido, uma região predefinida do endereço será
usada. Normalmente, esta é a região que aparece primeiro para no
dispositivo.
Muitos comandos têm variantes com sufixos d
, i
e o
(dados,
E/S e opcodes) que, por padrão, são as regiões do endereçamento nos
índices 1, 2 e 3, respectivamente, pois estes têm um
significado especial nos dispositivos do tipo CPU.
Em casos ambíguos, a região predefinida do endereçamento de um sub-dispositivo será usado no lugar de uma determinada região específica do endereço.
Exemplos:
ram
:ram
ou a ram
da região visível da CPU..:io
:io
ou o io
da região visível da CPU.:program
:program
ou o program
no dispositivo raiz do sistema.^vdp
vdp
.^:data
data
ou data
na região do dispositivo principal da região visível da CPU.1:rom
:rom
ou da rom
da 2ª CPU do sistema.2
Quando um comando toma como parâmetro um endereço emulado da memória, o endereço pode opcionalmente ser seguido por uma determinação na faixa de endereços, conforme descrito acima.
Exemplos:
0220
0220
na faixa de endereço padrão da região visível da CPU.0378:io
0378
na faixa de endereço padrão do dispositivo com a etiqueta absoluta :io
ou io
do endereçamento da região visível da CPU.1234:.:rom
1234
na faixa de endereço padrão no dispositivo relacionado da região visível da CPU com a etiqueta :rom
ou da rom
do endereçamento da região visível da CPU.1260:^vdp
1260
na faixa de endereço padrão do dispositivo irmão da região visível da CPU com a etiqueta vdp
.8008:^:data
8008
na faixa de endereço padrão do dispositivo irmão da região visível da CPU com a etiqueta :data
ou data
na região do dispositivo principal da região visível da CPU.9660::ram
9660
na faixa de endereço padrão do dispositivo com a etiqueta absoluta :ram
ou ram
no dispositivo raiz do sistema.Os exemplos aqui incluem muitos atalhos, mas geralmente, o depurador deve tomar o significado mais provável para um dispositivo ou uma especificação na região do endereçamento.
A sintaxe das expressões do depurador¶
As expressões podem ser usadas em qualquer lugar onde um parâmetro numérico ou um parâmetro booleano seja esperado. A sintaxe das expressões é semelhante a um subconjunto da sintaxe de expressão no estilo C, com precedência total do operador e dos parênteses. Faltam alguns operadores (notadamente o operador condicional ternário) e alguns novos (assessores da memória).
A tabela abaixo lista todos os operadores, ordenados da mais alta para a mais baixa prioridade:
(
)
++
--
++
--
~
!
-
+
b@
w@
d@
q@
b!
w!
d!
q!
*
/
%
+
-
<<
>>
<
<=
>
>=
==
!=
&
^
|
&&
||
=
*=
/=
%=
+=
-=
<<=
>>=
&=
|=
^=
,
As principais diferenças em relação à expressão semântica com C:
Todos os números são valores não assinados com 64-bits. Isso significa que números negativos não são permitidos.
A conjunção lógica e os operadores de disjunção
&&
e||
não apresentam propriedades de curto-circuito - ambos os lados da expressão são sempre avaliados.
Números¶
Os números literais são prefixados de acordo com suas respectivas bases:
Hexadecimal (base-16) com
$
or0x
.Decimal (base-10) com
#
.Octal (base-8) com
0o
.Binário (base-2) com
0b
.Números não prefixados são hexadecimais (base-16).
Exemplos:
123
é 123 em hexadecimal (291 decimal).$123
é 123 em hexadecimal (291 decimal).0x123
é 123 em hexadecimal (291 decimal).#123
é 123 em decimal.0o123
é 123 em octal (83 decimal).0b1001
é 1001 binário (9 decimal).0b123
é inválido.
Valores booleanos¶
Qualquer expressão que avalia até um número pode ser utilizado onde um
valor booleano seja necessário. Zero é tratado como falso, todos os
valores não zero são tratados como verdadeiros. Além disso, uma
string [3] true
é tratada como verdadeira e uma string
false
é tratada como falsa.
Uma expressão vazia pode ser apresentada como um argumento para que os parâmetros booleanos sejam usados como comandos padrão que possam ser usados para depuração, mesmo quando os parâmetros subsequentes sejam definidos.
Pode ser traduzido como cadeia de caracteres, cadência de caracteres, sequência de caracteres, caracteres, texto, linha, dentre outras variantes dependendo do contexto, mais informações.
Acesso à memória¶
Os operadores do prefixo de acesso à memória permitem a leitura e a escrita nas regiões dos endereços emulados. Os operadores do prefixo da memória determinam o tamanho do acesso e se os efeitos colaterais estão desativados, opcionalmente, podem ser precedidos por uma determinação na região do endereçamento. Os tamanhos do acesso suportado e os modos dos efeitos colaterais são:
b
determina um acesso 8-bit (byte).w
determina um acesso 16-bit (word).d
determina um acesso 32-bit (double word ou dword).q
determina um acesso 64-bit (quadruple word ou qword).@
suprime os efeitos colaterais.!
não suprime os efeitos colaterais.
Ao suprimir os efeitos colaterais de um acesso de leitura, a leitura do valor de um endereço seria obtida sem mais efeitos. Por exemplo, a leitura de uma "caixa postal" (mailbox) com efeitos colaterais desativada não limpará a sinalização que estiver pendente e a leitura de uma FIFO com os efeitos colaterais desativado, não fará a remoção de um item.
Nos acessos de escrita, ao suprimir os efeitos colaterais, o comportamento na maioria dos casos não é alterado, é preciso ver os efeitos da escrita no local. Entretanto, há algumas exceções onde é útil separar os diversos efeitos de um acesso de escrita, por exemplo:
Alguns registros precisam ser escritos em sequência para evitar as condições de corrida. O depurador pode emitir várias escritas no mesmo ponto no tempo da emulação, de modo que estas condições de corrida não possam ser evitadas de forma trivial. Por exemplo, a escrita para a saída do MC68HC05 compara o registro com byte alto (OCRH) e impede a comparação até que a saída compare o registro com byte baixo (OCRL) seja escrita para evitar as condições de corrida. Como o depurador pode escrever em ambos os locais ao mesmo tempo do ponto de vista do sistema que está sendo emulado, assim no geral, a condição de corrida não é relevante. Ela é mais propensa a erros quando se pode acidentalmente definir seu estado oculto quando tudo o que se realmente deseja fazer é alterar o valor, assim ao escrever no OCRH com efeitos colaterais suprimidos, ele não inibe a comparação, apenas altera o valor no registro do comparador da saída.
Ao escrever em alguns registros, os efeitos são diversos, o que pode ser útil para fins de depuração. Usando novamente o MC68HC05 como exemplo, ao escrever no OCRL o valor no registro de comparação da saída se altera e também limpa a sinalização de comparação da saída (OCF) permitindo comparar se ela foi anteriormente inibida durante a escrita no OCRH. A escrita no OCRL com efeitos colaterais desativado altera apenas o valor no registro sem apagar o OCF ou permite a comparação uma vez que é útil para a depuração. A escrita no OCRL com efeitos colaterais ativados tem efeitos adicionais.
Opcionalmente, o tamanho pode ser precedido por uma indicação do tipo de acesso:
p
oulp
define um endereço lógico predefinido para a região 0 (programa).d
ould
define um endereço lógico predefinido para a região 1 (dados).i
ouli
define um endereço lógico predefinido para a região 2 (E/S).3
oul3
define um endereço lógico predefinido para a região 3 (opcodes).pp
define um endereço físico predefinido para a região 0 (programa).pd
define um endereço físico predefinido para a região 1 (dados).pi
define um endereço físico predefinido para a região 2 (E/S).p3
define um endereço físico predefinido para a região 3 (opcodes).r
define um ponteiro de acesso predefinido de leitura/escrita para a região 0 (programa).o
define um ponteiro de acesso predefinido de leitura/escrita para a região 3 (opcodes).m
define uma região da memória.
Finalmente, isso pode ser precedido por uma etiqueta e/ou um nome na
região do endereçamento seguido por um ponto (.
).
Isso pode parecer muita coisa para ser assimilado, então vamos olhar nos exemplos mais simples:
b@<addr>
addr
> na região do programa da CPU atual enquanto estiver suprimindo os efeitos colaterais.b!<addr>
addr
> na região do programa da CPU atual enquanto não estiver suprimindo os efeitos colaterais como ao ler a "caixa de mensagens" (mailbox) limpando a sinalização pendente ou ao ler o FIFO removendo um item.w@<addr>
e w!<addr>
addr
> na região do programa da CPU atual suprimindo ou não respectivamente os efeitos colaterais.d@<addr>
e d!<addr>
addr
> na região do programa da CPU atual, respectivamente suprimindo ou não os efeitos colaterais.q@<addr>
e q!<addr>
addr
> na região do programa da CPU atual, respectivamente suprimindo ou não os efeitos colaterais.A adição dos tipos de acesso oferece possibilidades adicionais:
dw@300
300
na região de dados da CPU atual enquanto estiver suprimindo os efeitos colaterais.id@400
400
na região de E/S da CPU atual enquanto estiver suprimindo os efeitos colaterais.ppd!<addr>
addr
> na região do programa da CPU atual enquanto não estiver suprimindo os efeitos colaterais.rw@<addr>
addr
> na região do programa da CPU atual usando um ponteiro de acesso direto para leitura/escrita.Se quisermos acessar uma faixa de endereços de um dispositivo que não seja a CPU atual, uma faixa de endereços além dos quatro primeiros índices ou uma região da memória, precisamos incluir uma etiqueta ou um nome:
ramport.b@<addr>
addr
> na região ramport
na região do programa da CPU atual.audiocpu.dw@<addr>
addr
> na região de dados da CPU com a etiqueta absoluta :audiocpu
.maincpu:status.b@<addr>
addr
> na região status
da CPU com a etiqueta absoluta :maincpu
.monitor.mb@78
78
da memória com a etiqueta absoluta :monitor
...md@202
22
da região da memória com o mesmo caminho da etiqueta como a da CPU.Algumas combinações não são úteis. Os endereços físicos e lógicos por
exemplo, eles são equivalentes em algumas CPUs e o ponteiro de acesso
direto para a leitura/escrita nunca tem um efeito colateral. Ao acessar
a região da memória (acesso do tipo m
) é preciso que uma etiqueta
seja definida.
O acesso à memória pode ser usado com ambos os lvalues
e
rvalues
, assim é possível escrever b@100 = ff
para armazenar um
byte na memória.
Funções¶
O depurador suporta uma quantidade de funções úteis nas expressões.
min(<a>, <b>)
max(<a>, <b>)
if(<condição>, <valor_verdadeiro>, <valor_falso>)
valor_verdadeiro
> caso a <condição
> seja verdadeira (não zero), ou caso contrário, <valor_falso
>. Observe que ambas as expressões para <valor_verdadeiro
> e <valor_falso
> são ambos avaliados independentemente ainda que a <condição
> seja verdadeira ou falsa.abs(<x>)
bit(<x>, <n>[, <w>])
w
> a partir dos bits com largura <x
> na posição do bit de menor importância <n
>, contando a partir do bit menos importante. Caso <w
> seja omitido, um único bit é extraído.s8(<x>)
s16(<x>)
s32(<x>)