1
0
mirror of https://github.com/t-edson/P65Utils.git synced 2024-06-09 18:29:29 +00:00

Add files via upload

This commit is contained in:
Tito Hinostroza 2018-08-29 00:14:37 -05:00 committed by GitHub
parent 42cc492390
commit a662de2961
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 188 additions and 125 deletions

View File

@ -60,14 +60,13 @@ type //Models for RAM memory
function Getvalue: byte; function Getvalue: byte;
procedure Setvalue(AValue: byte); procedure Setvalue(AValue: byte);
public public
addr : word; //dirección física de memoria, en donde está la celda.
name : string; //Name of the register (for variables) name : string; //Name of the register (for variables)
used : boolean; //Indicates if have been written used : boolean; //Indicates if have been written
shared : boolean; //Used to share this register shared : boolean; //Used to share this register
state : TCPUCellState; //Status of the cell state : TCPUCellState; //Status of the cell
property value: byte read Getvalue write Setvalue; property value: byte read Getvalue write Setvalue;
property dvalue: byte read Fvalue write Fvalue; //Direct access to "Fvalue". property dvalue: byte read Fvalue write Fvalue; //Direct access to "Fvalue".
function AvailGPR: boolean; function Avail: boolean;
public //Campos para deputación public //Campos para deputación
breakPnt : boolean; //Indicates if this cell have a Breakpoint breakPnt : boolean; //Indicates if this cell have a Breakpoint
{Be careful on the size of this record, because it's going to be multiplied by 64K} {Be careful on the size of this record, because it's going to be multiplied by 64K}
@ -94,7 +93,7 @@ type
TCPUCore = class TCPUCore = class
public //Limits public //Limits
{This variables are set just one time. So they work as constant.} {This variables are set just one time. So they work as constant.}
CPUMAXRAM : word; //Max virtual RAM used by the CPU CPUMAXRAM: dword; //Max virtual RAM used by the CPU
public //General fields public //General fields
Model : string; //modelo de PIC Model : string; //modelo de PIC
frequen : integer; //frecuencia del reloj frequen : integer; //frecuencia del reloj
@ -106,8 +105,8 @@ type
CommStop: boolean; //Bandera para detener la ejecución CommStop: boolean; //Bandera para detener la ejecución
OnExecutionMsg: procedure(message: string) of object; //Genera mensaje en ejecución OnExecutionMsg: procedure(message: string) of object; //Genera mensaje en ejecución
protected //Generation of HEX files protected //Generation of HEX files
minUsed : word; //Dirección menor de la ROM usada minUsed : dword; //Dirección menor de la ROM usada
maxUsed : word; //Dirección mayor de la ROM usdas maxUsed : dword; //Dirección mayor de la ROM usdas
hexLines : TStringList; //Uusado para crear archivo *.hex hexLines : TStringList; //Uusado para crear archivo *.hex
public //Memories public //Memories
ram : TCPURam; //memoria RAM ram : TCPURam; //memoria RAM
@ -144,7 +143,7 @@ type
procedure ExecTo(endAdd: word); virtual; abstract; //Ejecuta hasta cierta dirección procedure ExecTo(endAdd: word); virtual; abstract; //Ejecuta hasta cierta dirección
procedure ExecStep; virtual; abstract; //Execute one instruction considering CALL as one instruction procedure ExecStep; virtual; abstract; //Execute one instruction considering CALL as one instruction
procedure ExecNCycles(nCyc: integer; out stopped: boolean); virtual; abstract; //Ejecuta hasta cierta dirección procedure ExecNCycles(nCyc: integer; out stopped: boolean); virtual; abstract; //Ejecuta hasta cierta dirección
procedure Reset; virtual; abstract; procedure Reset(hard: boolean); virtual; abstract;
function ReadPC: dword; virtual; abstract; //Defined DWORD to cover the 18F PC register function ReadPC: dword; virtual; abstract; //Defined DWORD to cover the 18F PC register
procedure WritePC(AValue: dword); virtual; abstract; procedure WritePC(AValue: dword); virtual; abstract;
public //Others public //Others
@ -168,7 +167,7 @@ procedure TCPURamCell.Setvalue(AValue: byte);
begin begin
Fvalue := AValue; Fvalue := AValue;
end; end;
function TCPURamCell.AvailGPR: boolean; function TCPURamCell.Avail: boolean;
{Indica si el registro es una dirección disponible en la memoria RAM.} {Indica si el registro es una dirección disponible en la memoria RAM.}
begin begin
Result := (state = cs_impleGPR); Result := (state = cs_impleGPR);
@ -211,7 +210,6 @@ var
i: word; i: word;
begin begin
for i:=0 to high(ram) do begin for i:=0 to high(ram) do begin
ram[i].addr := i;
ram[i].state := cs_unimplem; ram[i].state := cs_unimplem;
end; end;
//Inicia estado de pines //Inicia estado de pines
@ -542,7 +540,7 @@ end;
constructor TCPUCore.Create; constructor TCPUCore.Create;
begin begin
hexLines := TStringList.Create; hexLines := TStringList.Create;
frequen := 4000000; //4MHz frequen := 1000000; //4MHz
end; end;
destructor TCPUCore.Destroy; destructor TCPUCore.Destroy;
begin begin

View File

@ -167,8 +167,7 @@ type
W : byte; //Registro de trabajo W : byte; //Registro de trabajo
PC : TWordRec; //PC as record to fast access for bytes PC : TWordRec; //PC as record to fast access for bytes
PCLATH : byte; //Contador de Programa H PCLATH : byte; //Contador de Programa H
STKPTR : 0..7; //Puntero de pila SP : byte; //Puntero de pila
STACK : array[0..7] of word;
property STATUS: byte read GetSTATUS; property STATUS: byte read GetSTATUS;
property STATUS_Z: boolean read GetSTATUS_Z write SetSTATUS_Z; property STATUS_Z: boolean read GetSTATUS_Z write SetSTATUS_Z;
property STATUS_C: boolean read GetSTATUS_C write SetSTATUS_C; property STATUS_C: boolean read GetSTATUS_C write SetSTATUS_C;
@ -184,32 +183,31 @@ type
procedure ExecTo(endAdd: word); override; //Ejecuta hasta cierta dirección procedure ExecTo(endAdd: word); override; //Ejecuta hasta cierta dirección
procedure ExecStep; override; //Execute one instruction considering CALL as one instruction procedure ExecStep; override; //Execute one instruction considering CALL as one instruction
procedure ExecNCycles(nCyc: integer; out stopped: boolean); override; //Ejecuta hasta cierta dirección procedure ExecNCycles(nCyc: integer; out stopped: boolean); override; //Ejecuta hasta cierta dirección
procedure Reset; override; procedure Reset(hard: boolean); override;
function ReadPC: dword; override; function ReadPC: dword; override;
procedure WritePC(AValue: dword); override; procedure WritePC(AValue: dword); override;
public //Memories public //Memories
procedure Decode(const opCode: word); //decodifica instrucción procedure Decode(const opCode: word); //Decode instruction.
function Disassembler(const opCode, par1, par2: byte; out nBytesProc: byte;
useVarName: boolean=false): string; //Desensambla la instrucción actual
function DisassemblerAt(addr: word; out nBytesProc: byte; useVarName: boolean function DisassemblerAt(addr: word; out nBytesProc: byte; useVarName: boolean
): string; override; ): string; override;
public //Funciones para la memoria RAM public //RAM memory functions
function GetFreeByte(out addr: word; shared: boolean): boolean; function GetFreeByte(out addr: word; shared: boolean): boolean;
function GetFreeBytes(const size: integer; var addr: word): boolean; //obtiene una dirección libre function GetFreeBytes(const size: integer; var addr: word): boolean; //obtiene una dirección libre
function TotalMemRAM: word; //devuelve el total de memoria RAM function TotalMemRAM: integer; //devuelve el total de memoria RAM
function UsedMemRAM: word; //devuelve el total de memoria RAM usada function UsedMemRAM: word; //devuelve el total de memoria RAM usada
procedure ExploreUsed(rutExplorRAM: TCPURutExplorRAM); //devuelve un reporte del uso de la RAM procedure ExploreUsed(rutExplorRAM: TCPURutExplorRAM); //devuelve un reporte del uso de la RAM
function ValidRAMaddr(addr: word): boolean; //indica si una posición de memoria es válida function ValidRAMaddr(addr: word): boolean; //indica si una posición de memoria es válida
public //Métodos para codificar instrucciones de acuerdo a la sintaxis public //Métthods to code instructions according to syntax
procedure useRAM; procedure useRAM;
procedure codAsmFD(const inst: TP6502Inst; addMode: TP6502AddMode; param: word); procedure codAsm(const inst: TP6502Inst; addMode: TP6502AddMode; param: word);
procedure codGotoAt(iRam0: integer; const k: word); procedure codGotoAt(iRam0: integer; const k: word);
procedure codCallAt(iRam0: integer; const k: word); procedure codCallAt(iRam0: integer; const k: word);
function codInsert(iRam0, nInsert, nWords: integer): boolean; function codInsert(iRam0, nInsert, nWords: integer): boolean;
public //Métodos adicionales public //Adicional methods
function FindOpcode(Op: string): TP6502Inst; //busca Opcode function FindOpcode(Op: string): TP6502Inst; //busca Opcode
procedure GenHex(hexFile: string; ConfigWord: integer = - 1); //genera un archivo hex procedure GenHex(hexFile: string); //genera un archivo hex
procedure DumpCode(lOut: TStrings; incAdrr, incCom, incVarNam: boolean); //vuelva en código que contiene procedure DumpCodeAsm(lOut: TStrings; incAdrr, incValues, incCom,
incVarNam: boolean);
public //Initialization public //Initialization
constructor Create; override; constructor Create; override;
destructor Destroy; override; destructor Destroy; override;
@ -254,20 +252,20 @@ procedure TP6502.useRAM;
{Marca la posición actual, como usada, e incrementa el puntero iRam. Si hay error, {Marca la posición actual, como usada, e incrementa el puntero iRam. Si hay error,
actualiza el campo "MsjError"} actualiza el campo "MsjError"}
begin begin
//Protección de desborde
if iRam >= CPUMAXRAM then begin
MsjError := 'RAM Memory limit exceeded.';
exit;
end;
ram[iRam].used := true; //marca como usado ram[iRam].used := true; //marca como usado
inc(iRam); inc(iRam);
end; end;
procedure TP6502.codAsmFD(const inst: TP6502Inst; addMode: TP6502AddMode; param: word); procedure TP6502.codAsm(const inst: TP6502Inst; addMode: TP6502AddMode; param: word);
{Codifica las instrucciones orientadas a registro, con sintAxis: NEMÓNICO f,d} {Rutina general para codificar instrucciones en ensamblador}
var var
rInst: TP6502Instruct; rInst: TP6502Instruct;
begin begin
rInst := PIC16InstName[inst]; rInst := PIC16InstName[inst];
//Overflow protection
if iRam >= CPUMAXRAM then begin
MsjError := 'RAM Memory limit exceeded.';
exit;
end;
//Write OpCode //Write OpCode
ram[iRam].value := rInst.instrInform[addMode].Opcode; ram[iRam].value := rInst.instrInform[addMode].Opcode;
useRAM; //marca como usado e incrementa puntero. useRAM; //marca como usado e incrementa puntero.
@ -350,7 +348,6 @@ begin
raise Exception.Create('Implementation Error.'); raise Exception.Create('Implementation Error.');
end; end;
end; end;
procedure TP6502.codGotoAt(iRam0: integer; const k: word); procedure TP6502.codGotoAt(iRam0: integer; const k: word);
{Codifica una instrucción GOTO, en una posición específica y sin alterar el puntero "iFlash" {Codifica una instrucción GOTO, en una posición específica y sin alterar el puntero "iFlash"
actual. Se usa para completar saltos indefinidos} actual. Se usa para completar saltos indefinidos}
@ -362,7 +359,6 @@ begin
ram[iRam0+1].value := lo(k); ram[iRam0+1].value := lo(k);
ram[iRam0+2].value := hi(k); ram[iRam0+2].value := hi(k);
end; end;
procedure TP6502.codCallAt(iRam0: integer; const k: word); procedure TP6502.codCallAt(iRam0: integer; const k: word);
{Codifica una instrucción i_CALL, en una posición específica y sin alterar el puntero "iFlash" {Codifica una instrucción i_CALL, en una posición específica y sin alterar el puntero "iFlash"
actual. Se usa para completar llamadas indefinidas} actual. Se usa para completar llamadas indefinidas}
@ -372,7 +368,6 @@ begin
rInst := PIC16InstName[i_JSR]; rInst := PIC16InstName[i_JSR];
ram[iRam0].value := rInst.instrInform[aAbsolute].Opcode; ram[iRam0].value := rInst.instrInform[aAbsolute].Opcode;
end; end;
function TP6502.codInsert(iRam0, nInsert, nWords: integer): boolean; function TP6502.codInsert(iRam0, nInsert, nWords: integer): boolean;
{Inserta en la posición iRam0, "nInsert" palabras, desplazando "nWords" palabras. {Inserta en la posición iRam0, "nInsert" palabras, desplazando "nWords" palabras.
Al final debe quedar "nInsert" palabras de espacio libre en iRam0. Al final debe quedar "nInsert" palabras de espacio libre en iRam0.
@ -482,6 +477,7 @@ procedure TP6502.Decode(const opCode: word);
{Decode the value of "opCode" and update: {Decode the value of "opCode" and update:
* "idIns" -> Instruction ID * "idIns" -> Instruction ID
* "modIns" -> Address Mode * "modIns" -> Address Mode
If not found, returns "i_Inval" in "idIns".
} }
var var
i : TP6502Inst; i : TP6502Inst;
@ -497,91 +493,103 @@ begin
if iInfom.Opcode = opCode then begin if iInfom.Opcode = opCode then begin
idIns := i; idIns := i;
modIns := j; modIns := j;
exit;
end; end;
end; end;
end; end;
//Not found
idIns := i_Inval;
end; end;
function TP6502.Disassembler(const opCode, par1, par2: byte; function TP6502.DisassemblerAt(addr: word; out nBytesProc: byte;
out nBytesProc: byte; useVarName: boolean): string;
useVarName: boolean = false): string; {Disassembler the instruction located at "addr". If the instruction is multibyte
{Disassemble the instruction indicated in "Opcode". If the instruction is multibyte the intruction length, will be returned in "nBytesProc".
it will be used "par1" and "par2" according to the intruction length, which is returned
in "nBytesProc".
Global variables used: "idIns", "modIns". Global variables used: "idIns", "modIns".
"useVarName" -> Flag to use the name of the variable instead of only the address. "useVarName" -> Flag to use the name of the variable instead of only the address.
Valid only when a variAble name exists in his address. Valid only when a variAble name exists in his address.
} }
var var
nemo: String; nemo: String;
f: word; opCode, par1, par2: Byte;
begin begin
if addr>CPUMAXRAM-1 then exit('');
opCode := ram[addr].value;
//"par1" and "par2" will be used according to the instruction length.
if addr+1>CPUMAXRAM-1 then exit('');
par1 := ram[addr+1].value;
Decode(opCode); //Decode instruction. Update: "idIns", "modIns". Decode(opCode); //Decode instruction. Update: "idIns", "modIns".
nemo := trim(PIC16InstName[idIns].name) + ' '; nemo := trim(PIC16InstName[idIns].name) + ' ';
case modIns of case modIns of
aImplicit: begin aImplicit: begin
nBytesProc := 1; //No parameters needed nBytesProc := 1; //No parameters needed
Result := nemo;
end; end;
aAcumulat: begin aAcumulat: begin
nBytesProc := 1; //No parameters needed nBytesProc := 1; //No parameters needed
Result := nemo;
end; end;
aImmediat: begin aImmediat: begin
Result := nemo + '#$'+IntToHex(par1,2); Result := nemo + '#$'+IntToHex(par1,2);
nBytesProc := 2; nBytesProc := 2;
end; end;
aAbsolute: begin aAbsolute: begin
Result := nemo + '$'+IntToHex(par1 + par2*256, 4);
nBytesProc := 3; nBytesProc := 3;
if addr+2>CPUMAXRAM-1 then exit('');
par2 := ram[addr+2].value;
Result := nemo + '$'+IntToHex(par1 + par2*256, 4);
end; end;
aZeroPage: begin aZeroPage: begin
Result := nemo + '$'+IntToHex(par1, 2); Result := nemo + '$'+IntToHex(par1, 2);
nBytesProc := 2; nBytesProc := 2;
end; end;
aRelative: begin aRelative: begin
Result := nemo + '$'+IntToHex(par1, 2);
nBytesProc := 2; nBytesProc := 2;
if par1<128 then begin //Positive
Result := nemo + '$'+IntToHex((addr + par1+2) and $FFFF, 4);
end else begin
Result := nemo + '$'+IntToHex((addr + par1-254) and $FFFF, 4);
end;
//Result := nemo + '$'+IntToHex(par1, 2);
end; end;
aIndirect: begin aIndirect: begin
Result := nemo + '$('+IntToHex(par1 + par2*256, 4)+')';
nBytesProc := 3; nBytesProc := 3;
if addr+2>CPUMAXRAM-1 then exit('');
par2 := ram[addr+2].value;
Result := nemo + '$('+IntToHex(par1 + par2*256, 4)+')';
end; end;
aAbsolutX: begin aAbsolutX: begin
Result := nemo + '$'+IntToHex(par1 + par2*256, 4)+',X';
nBytesProc := 3; nBytesProc := 3;
if addr+2>CPUMAXRAM-1 then exit('');
par2 := ram[addr+2].value;
Result := nemo + '$'+IntToHex(par1 + par2*256, 4)+',X';
end; end;
aAbsolutY: begin aAbsolutY: begin
Result := nemo + '$'+IntToHex(par1 + par2*256, 4)+',Y';
nBytesProc := 3; nBytesProc := 3;
if addr+2>CPUMAXRAM-1 then exit('');
par2 := ram[addr+2].value;
Result := nemo + '$'+IntToHex(par1 + par2*256, 4)+',Y';
end; end;
aZeroPagX: begin aZeroPagX: begin
nBytesProc := 2;
Result := nemo + '$'+IntToHex(par1, 2)+',X'; Result := nemo + '$'+IntToHex(par1, 2)+',X';
nBytesProc := 3;
end; end;
aZeroPagY: begin aZeroPagY: begin
nBytesProc := 2;
Result := nemo + '$'+IntToHex(par1, 2)+',Y'; Result := nemo + '$'+IntToHex(par1, 2)+',Y';
nBytesProc := 3;
end; end;
aIdxIndir: begin aIdxIndir: begin
Result := nemo + '$('+IntToHex(par1, 2)+',X)';
nBytesProc := 2; nBytesProc := 2;
Result := nemo + '$('+IntToHex(par1, 2)+',X)';
end; end;
aIndirIdx: begin aIndirIdx: begin
nBytesProc := 2;
Result := nemo + '$('+IntToHex(par1, 2)+'),Y'; Result := nemo + '$('+IntToHex(par1, 2)+'),Y';
nBytesProc := 3;
end; end;
end; end;
end; end;
function TP6502.DisassemblerAt(addr: word; out nBytesProc: byte;
useVarName: boolean): string;
{Disassembler the instruction located at "addr"}
var
valOp: Word;
begin
Result := Disassembler(ram[addr].value,
ram[addr+1].value,
ram[addr+2].value, nBytesProc, useVarName);
end;
function TP6502.CurInstruction: TP6502Inst; function TP6502.CurInstruction: TP6502Inst;
{Resturn the instruction pointed by PC, in this moment.} {Return the instruction pointed by PC, in this moment.}
begin begin
Decode(ram[PC.W].value); //decode instruction Decode(ram[PC.W].value); //decode instruction
Result := idIns; Result := idIns;
@ -597,11 +605,11 @@ Falta implementar las operaciones, cuando acceden al registro INDF, el Watchdog
los contadores, las interrupciones} los contadores, las interrupciones}
var var
opc: byte; opc: byte;
msk, resNib: byte;
nCycles, nBytes: byte; nCycles, nBytes: byte;
resInt : integer; target : word;
begin begin
//Decodifica instrucción //Decodifica instrucción
aPC := PC.W;
opc := ram[aPC].value; opc := ram[aPC].value;
Decode(opc); //Decode instruction Decode(opc); //Decode instruction
nCycles := PIC16InstName[idIns].instrInform[modIns].Cycles; nCycles := PIC16InstName[idIns].instrInform[modIns].Cycles;
@ -635,24 +643,67 @@ begin
i_INC:; //increment i_INC:; //increment
i_INX:; //increment X i_INX:; //increment X
i_INY:; //increment Y i_INY:; //increment Y
i_JMP:; //jump i_JMP: begin //jump
i_JSR:; //jump subroutine case modIns of
aAbsolute : begin
PC.L := ram[aPC+1].value;
PC.H := ram[aPC+2].value;
end;
aIndirect: begin
target := ram[aPC+1].value + 256* ram[aPC+2].value;
PC.L := ram[target+1].value;
PC.H := ram[target+2].value;
end;
end;
//Inc(PC.W, nBytes); //No apply
Inc(nClck, nCycles);
exit;
end;
i_JSR: begin
inc(PC.W, 3); //Next psoition
//Save return
ram[$100 + SP].value := PC.H;
if SP = $00 then SP := $FF else dec(SP);
ram[$100 + SP].value := PC.L;
if SP = $00 then SP := $FF else dec(SP);
PC.L := ram[aPC+1].value;
PC.H := ram[aPC+2].value;
//Inc(PC.W, nBytes); //No apply
Inc(nClck, nCycles);
exit;
end; //jump subroutine
i_LDA:; //load accumulator i_LDA:; //load accumulator
i_LDX:; //load X i_LDX:; //load X
i_LDY:; //load Y i_LDY:; //load Y
i_LSR:; //logical shift right i_LSR:; //logical shift right
i_NOP:; //no operation i_NOP:; //no operation
i_ORA:; //or with accumulator i_ORA:; //or with accumulator
i_PHA:; //push accumulator i_PHA: begin //push accumulator
ram[$100 + SP].value := W;
if SP = $00 then SP := $FF else dec(SP);
end;
i_PHP:; //push processor status (SR) i_PHP:; //push processor status (SR)
i_PLA:; //pull accumulator i_PLA: begin //pull accumulator
if SP = $FF then SP := $00 else inc(SP);
W := ram[$100 + SP].value;
end;
i_PLP:; //pull processor status (SR) i_PLP:; //pull processor status (SR)
i_ROL:; //rotate left i_ROL:; //rotate left
i_ROR:; //rotate right i_ROR:; //rotate right
i_RTI:; //return from interrupt i_RTI:; //return from interrupt
i_RTS:; //return from subroutine i_RTS: begin //return from subroutine
if SP = $FF then SP := $00 else inc(SP);
PC.L := ram[$100 + SP].value;
if SP = $FF then SP := $00 else inc(SP);
PC.H := ram[$100 + SP].value;
//Inc(PC.W, nBytes); //No apply
Inc(nClck, nCycles);
exit;
end;
i_SBC:; //subtract with carry i_SBC:; //subtract with carry
i_SEC:; //set carry i_SEC: begin //set carry
STATUS_C := true;
end;
i_SED:; //set decimal i_SED:; //set decimal
i_SEI:; //set interrupt disable i_SEI:; //set interrupt disable
i_STA:; //store accumulator i_STA:; //store accumulator
@ -889,13 +940,13 @@ begin
end; end;
i_CALL: begin i_CALL: begin
//Guarda dirección en Pila //Guarda dirección en Pila
STACK[STKPTR] := PC.W; STACK[SP] := PC.W;
if STKPTR = 7 then begin if SP = 7 then begin
//Desborde de pila //Desborde de pila
STKPTR := 0; SP := 0;
if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on CALL OpCode at $' + IntToHex(aPC,4)); if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on CALL OpCode at $' + IntToHex(aPC,4));
end else begin end else begin
STKPTR := STKPTR +1; SP := SP +1;
end; end;
PC.W := k_; //Takes the 11 bits from k PC.W := k_; //Takes the 11 bits from k
PC.H := PC.H or (PCLATH and %00011000); //And complete with bits 3 and 4 of PCLATH PC.H := PC.H or (PCLATH and %00011000); //And complete with bits 3 and 4 of PCLATH
@ -920,42 +971,42 @@ begin
end; end;
i_RETFIE: begin i_RETFIE: begin
//Saca dirección en Pila //Saca dirección en Pila
if STKPTR = 0 then begin if SP = 0 then begin
//Desborde de pila //Desborde de pila
STKPTR := 7; SP := 7;
if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on RETFIE OpCode at $' + IntToHex(aPC,4)); if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on RETFIE OpCode at $' + IntToHex(aPC,4));
end else begin end else begin
STKPTR := STKPTR - 1; SP := SP - 1;
end; end;
PC.W := STACK[STKPTR]; //Should be 13 bits PC.W := STACK[SP]; //Should be 13 bits
Inc(nClck); //Esta instrucción toma un ciclo más Inc(nClck); //Esta instrucción toma un ciclo más
//Activa GIE //Activa GIE
INTCON_GIE := true; INTCON_GIE := true;
end; end;
i_RETLW: begin i_RETLW: begin
//Saca dirección en Pila //Saca dirección en Pila
if STKPTR = 0 then begin if SP = 0 then begin
//Desborde de pila //Desborde de pila
STKPTR := 7; SP := 7;
if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on RETLW OpCode at $' + IntToHex(aPC,4)); if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on RETLW OpCode at $' + IntToHex(aPC,4));
end else begin end else begin
STKPTR := STKPTR - 1; SP := SP - 1;
end; end;
PC.W := STACK[STKPTR]; //Should be 13 bits PC.W := STACK[SP]; //Should be 13 bits
Inc(nClck); //Esta instrucción toma un ciclo más Inc(nClck); //Esta instrucción toma un ciclo más
//Fija valor en W //Fija valor en W
W := k_; W := k_;
end; end;
i_RETURN: begin i_RETURN: begin
//Saca dirección en Pila //Saca dirección en Pila
if STKPTR = 0 then begin if SP = 0 then begin
//Desborde de pila //Desborde de pila
STKPTR := 7; SP := 7;
if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on RETURN OpCode at $' + IntToHex(aPC,4)); if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on RETURN OpCode at $' + IntToHex(aPC,4));
end else begin end else begin
STKPTR := STKPTR - 1; SP := SP - 1;
end; end;
PC.W := STACK[STKPTR]; //Should be 13 bits PC.W := STACK[SP]; //Should be 13 bits
Inc(nClck); //Esta instrucción toma un ciclo más Inc(nClck); //Esta instrucción toma un ciclo más
end; end;
i_SLEEP: begin i_SLEEP: begin
@ -1053,7 +1104,7 @@ begin
end; end;
stopped := false; stopped := false;
end; end;
procedure TP6502.Reset; procedure TP6502.Reset(hard: boolean);
//Reinicia el dipsoitivo //Reinicia el dipsoitivo
var var
i: Integer; i: Integer;
@ -1061,12 +1112,14 @@ begin
PC.W := 0; PC.W := 0;
PCLATH := 0; PCLATH := 0;
W := 0; W := 0;
STKPTR := 0; //Posición inicial del puntero de pila SP := $FF; //Posición inicial del puntero de pila
nClck := 0; //Inicia contador de ciclos nClck := 0; //Inicia contador de ciclos
CommStop := false; //Limpia bandera CommStop := false; //Limpia bandera
//Limpia solamente el valor inicial, no toca los otros campos if hard then begin
for i:=0 to high(ram) do begin //Limpia solamente el valor inicial, no toca los otros campos
ram[i].dvalue := $00; for i:=0 to high(ram) do begin
ram[i].dvalue := $00;
end;
end; end;
ram[_STATUS].dvalue := %00011000; //STATUS ram[_STATUS].dvalue := %00011000; //STATUS
end; end;
@ -1080,18 +1133,18 @@ begin
end; end;
//Funciones para la memoria RAM //Funciones para la memoria RAM
function TP6502.GetFreeByte(out addr: word; shared: boolean): boolean; function TP6502.GetFreeByte(out addr: word; shared: boolean): boolean;
{Devuelve una dirección libre de la memoria RAM. {Devuelve una dirección libre de la memoria RAM, a partir de la dirección iRam.
"Shared" indica que se marcará el bit como de tipo "Compartido", y se usa para el "Shared" indica que se marcará el bit como de tipo "Compartido", y se usa para el
caso en que se quiera comaprtir la misma posición para diversos variables. caso en que se quiera comaprtir la misma posición para diversos variables.
Si encuentra espacio, devuelve TRUE.} Si encuentra espacio, devuelve TRUE.}
var var
i: Integer; i: Integer;
maxRam: word; maxRam: dword;
begin begin
Result := false; //valor inicial Result := false; //valor inicial
maxRam := CPUMAXRAM; //posición máxima maxRam := CPUMAXRAM; //posición máxima
//Realmente debería explorar solo hasta la dirección implementada, por eficiencia //Realmente debería explorar solo hasta la dirección implementada, por eficiencia
for i:=0 to maxRam-1 do begin for i:=iRam to maxRam-1 do begin
if (ram[i].state = cs_impleGPR) and (not ram[i].used) then begin if (ram[i].state = cs_impleGPR) and (not ram[i].used) then begin
//Esta dirección está libre //Esta dirección está libre
ram[i].used := true; //marca como usado ram[i].used := true; //marca como usado
@ -1126,14 +1179,14 @@ begin
end; end;
end; end;
end; end;
function TP6502.TotalMemRAM: word; function TP6502.TotalMemRAM: integer;
{Devuelve el total de memoria RAM disponible} {Devuelve el total de memoria RAM disponible}
var var
i: Integer; i: Integer;
begin begin
Result := 0; Result := 0;
for i := 0 to CPUMAXRAM - 1 do begin for i := 0 to CPUMAXRAM - 1 do begin
if ram[i].AvailGPR then begin if ram[i].Avail then begin
Result := Result + 1; Result := Result + 1;
end; end;
end; end;
@ -1145,7 +1198,7 @@ var
begin begin
Result := 0; Result := 0;
for i := 0 to CPUMAXRAM - 1 do begin for i := 0 to CPUMAXRAM - 1 do begin
if ram[i].AvailGPR and (ram[i].used) then begin if ram[i].Avail and (ram[i].used) then begin
//Notar que "AvailGPR" asegura que no se consideran registros maepados //Notar que "AvailGPR" asegura que no se consideran registros maepados
Result := Result + 1; Result := Result + 1;
end; end;
@ -1157,7 +1210,7 @@ var
i: Integer; i: Integer;
begin begin
for i := 0 to CPUMAXRAM - 1 do begin for i := 0 to CPUMAXRAM - 1 do begin
if ram[i].AvailGPR and (ram[i].used) then begin if ram[i].Avail and (ram[i].used) then begin
rutExplorRAM(i, @ram[i]); rutExplorRAM(i, @ram[i]);
end; end;
end; end;
@ -1168,37 +1221,13 @@ begin
if addr > CPUMAXRAM then exit(false); //excede límite if addr > CPUMAXRAM then exit(false); //excede límite
exit(true); exit(true);
end; end;
procedure TP6502.GenHex(hexFile: string; ConfigWord: integer = -1); procedure TP6502.DumpCodeAsm(lOut: TStrings;
{Genera el archivo *.hex, a partir de los datos almacenados en la memoria RAM. incAdrr, incValues, incCom, incVarNam: boolean);
Actualiza los campos, minUsed y maxUsed.}
var
iHex: word; //Índice para explorar
addr: word; //Dirección de inicio
i: Integer;
begin
hexLines.Clear; //Se usará la lista hexLines
//Prepara extracción de datos
minUsed := CPUMAXRAM;
maxUsed := 0;
iHex := 0;
//Busca dirección de inicio usada
for i := 0 to CPUMAXRAM-1 do begin
if ram[i].used then begin
if i<minUsed then minUsed := i;
if i>maxUsed then maxUsed := i;
hexLines.Add('poke ' + IntToStr(i) + ',' + IntToStr(ram[i].value));
end;
end;
//hexLines.Add('Comentario');
hexLines.SaveToFile(hexFile); //Genera archivo
end;
procedure TP6502.DumpCode(lOut: TStrings; incAdrr, incCom, incVarNam: boolean);
{Desensambla las instrucciones grabadas en el PIC. {Desensambla las instrucciones grabadas en el PIC.
Se debe llamar despues de llamar a GenHex(), para que se actualicen las variables} Se debe llamar despues de llamar a GenHex(), para que se actualicen las variables}
var var
i: Word; i: Word;
lblLin, comLat, comLin, lin: String; lblLin, comLat, comLin, lin, opCode: String;
nBytes: byte; nBytes: byte;
const const
SPACEPAD = ' '; SPACEPAD = ' ';
@ -1233,11 +1262,27 @@ begin
lOut.Add(comLin); lOut.Add(comLin);
end; end;
//Decodifica instrucción //Decodifica instrucción
lin := DisassemblerAt(i, nBytes, incVarNam); //Instrucción opCode := DisassemblerAt(i, nBytes, incVarNam); //Instrucción
//Verificas si incluye dirección física //Verificas si incluye dirección física
lin := '';
if incAdrr then begin if incAdrr then begin
lin := '$'+IntToHex(i,4) + ' ' + lin; //Agrega dirección al inicio
lin := '$'+IntToHex(i,4) + ' ';
end; end;
if incValues then begin
//Agrega bytes después
if nBytes = 1 then begin
lin := lin + IntToHex(ram[i].value, 2) + ' ' ;
end else if nBytes = 2 then begin
lin := lin + IntToHex(ram[i].value, 2) + ' ' +
IntToHex(ram[i+1].value, 2) + ' ';
end else if nBytes = 3 then begin
lin := lin + IntToHex(ram[i].value, 2) + ' ' +
IntToHex(ram[i+1].value, 2) + ' ' +
IntToHex(ram[i+2].value, 2) + ' ';
end;
end;
lin := lin + opCode;
//Verifica si incluye comentario lateral //Verifica si incluye comentario lateral
if incCom then begin if incCom then begin
lin := lin + ' ' + comLat; lin := lin + ' ' + comLat;
@ -1246,12 +1291,32 @@ begin
i := i + nBytes; //Incrementa a siguiente instrucción i := i + nBytes; //Incrementa a siguiente instrucción
end; end;
end; end;
procedure TP6502.GenHex(hexFile: string);
{Genera el archivo *.hex, a partir de los datos almacenados en la memoria RAM.
Actualiza los campos, minUsed y maxUsed.}
var
i: Integer;
begin
hexLines.Clear; //Se usará la lista hexLines
//Prepara extracción de datos
minUsed := CPUMAXRAM;
maxUsed := 0;
//Busca dirección de inicio usada
for i := 0 to CPUMAXRAM-1 do begin
if ram[i].used then begin
if i<minUsed then minUsed := i;
if i>maxUsed then maxUsed := i;
hexLines.Add('poke ' + IntToStr(i) + ',' + IntToStr(ram[i].value));
end;
end;
hexLines.SaveToFile(hexFile); //Genera archivo
end;
constructor TP6502.Create; constructor TP6502.Create;
begin begin
inherited Create; inherited Create;
//Default hardware settings //Default hardware settings
Model := '6502'; Model := '6502';
CPUMAXRAM := 4096; //Máx RAM memory CPUMAXRAM := $10000; //Máx RAM memory
SetLength(ram, CPUMAXRAM); SetLength(ram, CPUMAXRAM);
//inicia una configuración común //inicia una configuración común
ClearMemRAM; ClearMemRAM;