diff --git a/Cambios.txt b/Cambios.txt
index 7a972c5..fae5ced 100644
--- a/Cambios.txt
+++ b/Cambios.txt
@@ -1,3 +1,8 @@
+0.5
+===
+04/09/2020: Se mueve el m閠odo FindOpcode() fuera del objeto TP6502Instruct.
+22/10/2020: Se agrega protecci髇 de direcci髇 excesiva, a TCPUCore.addTopLabel().
+
0.4
===
Se corrige un error con la ejecuci髇 de la instrucci髇 ROL.
diff --git a/MiniAssembler/project1.lps b/MiniAssembler/project1.lps
index fb90206..b79f23d 100644
--- a/MiniAssembler/project1.lps
+++ b/MiniAssembler/project1.lps
@@ -21,18 +21,18 @@
+
-
+
-
-
-
+
+
diff --git a/P6502utils.pas b/P6502utils.pas
index b85399f..7d7a3cb 100644
--- a/P6502utils.pas
+++ b/P6502utils.pas
@@ -203,7 +203,6 @@ type
procedure cod_REL_JMP_at(iRam0: integer; const k: word);
function codInsert(iRam0, nInsert, nWords: integer): boolean;
public //Aditional methods
- function FindOpcode(Op: string): TP6502Inst; //Find Opcode
function IsRelJump(idInst: TP6502Inst): boolean; //Idnetify realtive jumps Opcodes
procedure GenHex(hexFile: string; startAddr: integer = - 1); //genera un archivo hex
procedure DumpCodeAsm(lOut: TStrings; incAdrr, incValues, incCom,
@@ -217,8 +216,31 @@ var //Global variables
//mnem贸nico de las instrucciones
PIC16InstName: array[low(TP6502Inst)..high(TP6502Inst)] of TP6502Instruct;
+
+ function FindOpcode(txt: string; out opCode: TP6502Inst): boolean;
+
implementation
+function FindOpcode(txt: string; out opCode: TP6502Inst): boolean;
+{Search a string that represent an instruction (Opcode). If found, returns TRUE and
+the instruction identifier in "opCode", otherwise returns FALSE and "i_Inval" in
+"opCode". }
+var
+ idInst: TP6502Inst;
+ tmp: String;
+begin
+ tmp := UpperCase(txt);
+ for idInst := low(TP6502Inst) to high(TP6502Inst) do begin
+ if PIC16InstName[idInst].name = tmp then begin
+ opCode := idInst;
+ exit(true);
+ end;
+ end;
+ //No found.
+ opCode := i_Inval;
+ exit(false);
+end;
+
{ TP6502Instruct }
procedure TP6502Instruct.Init(name0: string);
@@ -390,29 +412,6 @@ begin
ram[i] := ram[i-nInsert];
end;
end;
-//procedure TP6502.BTFSC_sw_BTFSS(iRam0: integer);
-//{Exchange instruction i_BTFSC to i_BTFSS, or viceversa, in the specified address.}
-//begin
-// //Solo necesita cambiar el bit apropiado
-// ram[iRam0].value := ram[iRam0].value XOR %10000000000;
-//end;
-function TP6502.FindOpcode(Op: string): TP6502Inst;
-{Search a string that represent an instruction (Opcode). If found, returns the
-instruction identifier, otherwise returns "i_Inval". }
-var
- idInst: TP6502Inst;
- tmp: String;
-begin
- tmp := UpperCase(Op);
- for idInst := low(TP6502Inst) to high(TP6502Inst) do begin
- if PIC16InstName[idInst].name = tmp then begin
- Result := idInst;
- exit;
- end;
- end;
- //No found.
- Result := i_Inval;
-end;
function TP6502.IsRelJump(idInst: TP6502Inst): boolean;
{Returns TRUE if the instruction accept the relative address mode}
begin
diff --git a/P65C02utils.pas b/P65C02utils.pas
new file mode 100644
index 0000000..b85399f
--- /dev/null
+++ b/P65C02utils.pas
@@ -0,0 +1,1651 @@
+{
+Description
+===========
+Utilities for the 6502 CPU. The types here defined are intended to be used for:
+* Assembling 6502 instructions.
+* Disassembling 6502 instructions.
+* Simulating the 6502 execution.
+To simulate the CPU, it's assumed there are 64KB of RAM in a virtual system.
+The main class TP6502 models a CPU6502 object including access to 64KB RAM.
+The aim of this unit is to be used as base for assemblers, compilers and simulators.
+
+ Created by Tito Hinostroza 19/05/2018
+}
+
+unit P6502utils;
+{$mode objfpc}{$H+}
+interface
+uses
+ Classes, SysUtils, LCLProc, CPUCore, strutils;
+type //Instructions set
+ TP6502Inst = (
+ i_ADC, //add with carry
+ i_AND, //and (with accumulator)
+ i_ASL, //arithmetic shift left
+ i_BCC, //branch on carry clear
+ i_BCS, //branch on carry set
+ i_BEQ, //branch on equal (zero set)
+ i_BIT, //bit test
+ i_BMI, //branch on minus (negative set)
+ i_BNE, //branch on not equal (zero clear)
+ i_BPL, //branch on plus (negative clear)
+ i_BRK, //break / interrupt
+ i_BVC, //branch on overflow clear
+ i_BVS, //branch on overflow set
+ i_CLC, //clear carry
+ i_CLD, //clear decimal
+ i_CLI, //clear interrupt disable
+ i_CLV, //clear overflow
+ i_CMP, //compare (with accumulator)
+ i_CPX, //compare with X
+ i_CPY, //compare with Y
+ i_DEC, //decrement
+ i_DEX, //decrement X
+ i_DEY, //decrement Y
+ i_EOR, //exclusive or (with accumulator)
+ i_INC, //increment
+ i_INX, //increment X
+ i_INY, //increment Y
+ i_JMP, //jump
+ i_JSR, //jump subroutine
+ i_LDA, //load accumulator
+ i_LDX, //load X
+ i_LDY, //load Y
+ i_LSR, //logical shift right
+ i_NOP, //no operation
+ i_ORA, //or with accumulator
+ i_PHA, //push accumulator
+ i_PHP, //push processor status (SR)
+ i_PLA, //pull accumulator
+ i_PLP, //pull processor status (SR)
+ i_ROL, //rotate left
+ i_ROR, //rotate right
+ i_RTI, //return from interrupt
+ i_RTS, //return from subroutine
+ i_SBC, //subtract with carry
+ i_SEC, //set carry
+ i_SED, //set decimal
+ i_SEI, //set interrupt disable
+ i_STA, //store accumulator
+ i_STX, //store X
+ i_STY, //store Y
+ i_TAX, //transfer accumulator to X
+ i_TAY, //transfer accumulator to Y
+ i_TSX, //transfer stack pointer to X
+ i_TXA, //transfer X to accumulator
+ i_TXS, //transfer X to stack pointer
+ i_TYA, //transfer Y to accumulator
+ //INVALID INSTRUCTION
+ i_Inval
+ );
+ //Addressing Modes
+ {Implicit Mode and Acumulator Mode are not considered here. We consider
+ Only Modes with parameters.}
+ TP6502AddMode = (
+ aImplicit, //Implied : BRK
+ aAcumulat, //Acumulator : ASL
+ aImmediat, //Immediate : ORA #$B2
+ aAbsolute, //Absolute : JMP $4032
+ aZeroPage, //Zero page : LDA: $35
+ aRelative, //Relative : BNE LABEL
+ aIndirect, //Indirect : JMP ($1000)
+ aAbsolutX, //Absolute Indexed by X : STA $1000, X
+ aAbsolutY, //Absolute Indexed by Y : STA $1000, Y
+ aZeroPagX, //Zero page Indexed by X : LDA $10, X
+ aZeroPagY, //Zero page Indexed by Y : LDA $10, Y
+ aIndirecX, //Indexed Indirect: LDA ($40,X) Only for X
+ aIndirecY //Indirect Indexed: LDA ($40),Y Only for Y
+ );
+ TP6502AddModes = set of TP6502AddMode;
+ //Instruction Information for each Address Mode
+ TInstructInform = record
+ Opcode: byte; //Code for instruction
+ nBytes: byte; //Num. of bytes of the instruction.
+ Cycles: byte; //Num. of cycles the instruction takes.
+ optCycles: string; //Extra options in Num. of cycles.
+ end;
+
+ //Record for a 6502 instruction
+
+ { TP6502Instruct }
+
+ TP6502Instruct = object
+ public
+ //Name of the instruction
+ name: string[3];
+ //Address Modes supported
+ addressModes: TP6502AddModes;
+ //Information for each Address Mode supported
+ instrInform: array[TP6502AddMode] of TInstructInform;
+ public
+ procedure Init(name0: string);
+ procedure AddAddressMode(aMode: TP6502AddMode; Opcode, nBytes, nCycles: Byte;
+ optCycles: string);
+ end;
+
+const //Constants of address and bit positions for some registers
+ _C = 0;
+ _Z = 1;
+ _D = 3;
+ _B = 4;
+ _V = 6;
+ _N = 7;
+// _IRP = 7;
+type
+ {Object representing CPU6502 hardware}
+ { TP6502 }
+ TP6502 = class(TCPUCore)
+ public //Fields to disassembler instructions
+ idIns: TP6502Inst; //Instruction ID
+ modIns: TP6502AddMode; //Address mode
+ parIns: word; //Instruction parameter. Only valid for some instructions.
+ private //Fields to process instructions
+ function GetINTCON: byte;
+ function GetINTCON_GIE: boolean;
+ function GetSTATUS_C: boolean;
+ function GetSTATUS_D: boolean;
+ function GetSTATUS_N: boolean;
+ function GetSTATUS_I: boolean;
+ function GetSTATUS_V: boolean;
+ function GetSTATUS_Z: boolean;
+ procedure SetINTCON_GIE(AValue: boolean);
+ procedure SetSTATUS_C(AValue: boolean);
+ procedure SetSTATUS_D(AValue: boolean);
+ procedure SetSTATUS_N(AValue: boolean);
+ procedure SetSTATUS_I(AValue: boolean);
+ procedure SetSTATUS_V(AValue: boolean);
+ procedure SetSTATUS_Z(AValue: boolean);
+ procedure SetFRAM(value: byte);
+ function GetFRAM: byte;
+ public //Fields to modelate internal register (For Simulation)
+ W : byte; //Work register
+ X,Y : byte; //Index registers
+ PC : TWordRec; //PC as record to fast access for bytes
+ SP : byte; //Stack Pointer
+ SR : byte; //Status Register
+ property STATUS: byte read SR;
+ property STATUS_N: boolean read GetSTATUS_N write SetSTATUS_N;
+ property STATUS_V: boolean read GetSTATUS_V write SetSTATUS_V;
+ property STATUS_D: boolean read GetSTATUS_D write SetSTATUS_D;
+ property STATUS_I: boolean read GetSTATUS_I write SetSTATUS_I;
+ property STATUS_Z: boolean read GetSTATUS_Z write SetSTATUS_Z;
+ property STATUS_C: boolean read GetSTATUS_C write SetSTATUS_C;
+ property INTCON: byte read GetINTCON;
+ property INTCON_GIE: boolean read GetINTCON_GIE write SetINTCON_GIE;
+ property FRAM: byte read GetFRAM write SetFRAM;
+ public //Execution control
+ function CurInstruction: TP6502Inst;
+ procedure Exec(aPC: word); override; //Ejecuta la instrucci贸n en la direcci贸n indicada.
+ procedure Exec; override; //Ejecuta instrucci贸n actual
+ procedure ExecTo(endAdd: word); override; //Ejecuta hasta cierta direcci贸n
+ 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 Reset(hard: boolean); override;
+ function ReadPC: dword; override;
+ procedure WritePC(AValue: dword); override;
+ public //Memories
+ procedure Decode(const opCode: word); //Decode instruction.
+ function DisassemblerAt(addr: word; out nBytesProc: byte; useVarName: boolean
+ ): string; override;
+ public //RAM memory functions
+ freeStart: word; //Start address where Free RAM will be searched.
+ function GetFreeByte(out addr: word): boolean;
+ function GetFreeBytes(const size: integer; out addr: word): boolean; //obtiene una direcci贸n libre
+ function TotalMemRAM: integer; //devuelve el total de memoria RAM
+ function UsedMemRAM: word; //devuelve el total de memoria RAM usada
+ 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
+ public //Methods to code instructions according to syntax
+ procedure useRAMCode;
+ procedure codByte(const value: byte; isData: boolean);
+ procedure codAsm(const inst: TP6502Inst; addMode: TP6502AddMode; param: word);
+ procedure cod_JMP_at(iRam0: integer; const k: word);
+ procedure cod_REL_JMP_at(iRam0: integer; const k: word);
+ function codInsert(iRam0, nInsert, nWords: integer): boolean;
+ public //Aditional methods
+ function FindOpcode(Op: string): TP6502Inst; //Find Opcode
+ function IsRelJump(idInst: TP6502Inst): boolean; //Idnetify realtive jumps Opcodes
+ procedure GenHex(hexFile: string; startAddr: integer = - 1); //genera un archivo hex
+ procedure DumpCodeAsm(lOut: TStrings; incAdrr, incValues, incCom,
+ incVarNam: boolean);
+ public //Initialization
+ constructor Create; override;
+ destructor Destroy; override;
+ end;
+
+var //Global variables
+ //mnem贸nico de las instrucciones
+ PIC16InstName: array[low(TP6502Inst)..high(TP6502Inst)] of TP6502Instruct;
+
+implementation
+
+{ TP6502Instruct }
+
+procedure TP6502Instruct.Init(name0: string);
+//Initialize the instruction. Must be called before AddAddressMode().
+begin
+ name := name0; //Set
+ addressModes:= []; //Clear
+end;
+procedure TP6502Instruct.AddAddressMode(aMode: TP6502AddMode;
+ Opcode, nBytes, nCycles: Byte;
+ optCycles: string);
+{Add a new Address Mode including additional information.
+"optCycles" is a flag and indicate aditional considerations on cycles:
+
+'*' -> Add 1 to cycles if page boundery is crossed
+
+'**' -> Add 1 to cycles if branch occurs on same page
+ Add 2 to cycles if branch occurs to different page
+}
+begin
+ addressModes := addressModes + [aMode]; //Register Mode
+ //Add information
+ instrInform[aMode].Opcode:= Opcode;
+ instrInform[aMode].nBytes:= nBytes;
+ instrInform[aMode].Cycles:= nCycles;
+ instrInform[aMode].optCycles := optCycles;
+end;
+
+{ TP6502 }
+procedure TP6502.useRAMCode;
+{Set current position as used and increase the index iRam. If error;update "MsjError"}
+begin
+ ram[iRam].used := ruCode; //Mark as used.
+ inc(iRam);
+end;
+procedure TP6502.codByte(const value: byte; isData: boolean);
+{Write a byte to the RAM memory.}
+begin
+ if iRam >= CPUMAXRAM then begin
+ MsjError := 'RAM Memory limit exceeded.';
+ exit;
+ end;
+ ram[iRam].value := value;
+ if isData then ram[iRam].name := 'data';
+ ram[iRam].used := ruData; //Mark as used.
+ inc(iRam);
+end;
+procedure TP6502.codAsm(const inst: TP6502Inst; addMode: TP6502AddMode; param: word);
+{General routine to codify assembler instructions.}
+var
+ rInst: TP6502Instruct;
+begin
+ rInst := PIC16InstName[inst];
+ //Overflow protection
+ if iRam >= CPUMAXRAM then begin
+ MsjError := 'RAM Memory limit exceeded.';
+ exit;
+ end;
+ //Write OpCode
+ if not (addMode in rInst.addressModes) then begin
+ MsjError := 'Invalid Adrress mode.';
+ exit;
+ end;
+ ram[iRam].value := rInst.instrInform[addMode].Opcode;
+ useRAMCode; //Set as used and increase index.
+ //Encode parameters
+ case addMode of
+ aImplicit: begin
+ //No parameters
+ if addMode in rInst.addressModes then begin
+ //It's OK
+ end else begin
+ MsjError:= 'Invalid Address Mode (Implicit)';
+ end;
+ end;
+ aAcumulat: begin
+ //No parameters
+ if addMode in rInst.addressModes then begin
+ //It's OK
+ end else begin
+ MsjError:= 'Invalid Address Mode (Acumulator)';
+ end;
+ end;
+ aImmediat: begin
+ if addMode in rInst.addressModes then begin
+ //It's OK
+ end else begin
+ MsjError:= 'Invalid Address Mode (Immediate)';
+ end;
+ ram[iRam].value := lo(param); //escribe par谩metro
+ useRAMCode;
+ end;
+ aAbsolute:begin
+ ram[iRam].value := lo(param);
+ useRAMCode;
+ ram[iRam].value := hi(param);
+ useRAMCode;
+ end;
+ aZeroPage:begin
+ ram[iRam].value := lo(param);
+ useRAMCode;
+ end;
+ aRelative:begin
+ ram[iRam].value := lo(param);
+ useRAMCode;
+ end;
+ aIndirect:begin
+ ram[iRam].value := lo(param);
+ useRAMCode;
+ ram[iRam].value := hi(param);
+ useRAMCode;
+ end;
+ aAbsolutX:begin
+ ram[iRam].value := lo(param);
+ useRAMCode;
+ ram[iRam].value := hi(param);
+ useRAMCode;
+ end;
+ aAbsolutY:begin
+ ram[iRam].value := lo(param);
+ useRAMCode;
+ ram[iRam].value := hi(param);
+ useRAMCode;
+ end;
+ aZeroPagX:begin
+ ram[iRam].value := lo(param);
+ useRAMCode;
+ end;
+ aZeroPagY:begin
+ ram[iRam].value := lo(param);
+ useRAMCode;
+ end;
+ aIndirecX:begin
+ ram[iRam].value := lo(param);
+ useRAMCode;
+ end;
+ aIndirecY:begin
+ ram[iRam].value := lo(param);
+ useRAMCode;
+ end;
+ else
+ raise Exception.Create('Implementation Error.');
+ end;
+end;
+procedure TP6502.cod_JMP_at(iRam0: integer; const k: word);
+{Encode the jump address for a jump instruction. Used to complete undefined jumps.}
+begin
+ ram[iRam0+1].value := lo(k);
+ ram[iRam0+2].value := hi(k);
+end;
+procedure TP6502.cod_REL_JMP_at(iRam0: integer; const k: word);
+{Encode the jump address for a relative jump instruction. Used to complete undefined jumps.}
+begin
+ ram[iRam0+1].value := lo(k);
+end;
+function TP6502.codInsert(iRam0, nInsert, nWords: integer): boolean;
+{Inserta en la posici贸n iRam0, "nInsert" palabras, desplazando "nWords" palabras.
+Al final debe quedar "nInsert" palabras de espacio libre en iRam0.
+Si hay error devuelve FALSE.}
+var
+ i: Integer;
+begin
+ Result := True; //By default
+ if iRam+nInsert+nWords-1> CPUMAXRAM then begin
+ //Overflow on address
+ exit(false);
+ end;
+ for i:= iRam + nInsert + nWords -1 downto iRam + nWords do begin
+ ram[i] := ram[i-nInsert];
+ end;
+end;
+//procedure TP6502.BTFSC_sw_BTFSS(iRam0: integer);
+//{Exchange instruction i_BTFSC to i_BTFSS, or viceversa, in the specified address.}
+//begin
+// //Solo necesita cambiar el bit apropiado
+// ram[iRam0].value := ram[iRam0].value XOR %10000000000;
+//end;
+function TP6502.FindOpcode(Op: string): TP6502Inst;
+{Search a string that represent an instruction (Opcode). If found, returns the
+instruction identifier, otherwise returns "i_Inval". }
+var
+ idInst: TP6502Inst;
+ tmp: String;
+begin
+ tmp := UpperCase(Op);
+ for idInst := low(TP6502Inst) to high(TP6502Inst) do begin
+ if PIC16InstName[idInst].name = tmp then begin
+ Result := idInst;
+ exit;
+ end;
+ end;
+ //No found.
+ Result := i_Inval;
+end;
+function TP6502.IsRelJump(idInst: TP6502Inst): boolean;
+{Returns TRUE if the instruction accept the relative address mode}
+begin
+ Result := PIC16InstName[idInst].instrInform[aRelative].Opcode<>0;
+end;
+//Campos para procesar instrucciones
+function TP6502.GetSTATUS_N: boolean;
+begin
+ Result := (SR and %10000000) <> 0;
+end;
+procedure TP6502.SetSTATUS_N(AValue: boolean);
+begin
+ if AVAlue then SR := SR or %10000000
+ else SR := SR and %01111111;
+end;
+function TP6502.GetSTATUS_V: boolean;
+begin
+ Result := (SR and %01000000) <> 0;
+end;
+procedure TP6502.SetSTATUS_V(AValue: boolean);
+begin
+ if AVAlue then SR := SR or %01000000
+ else SR := SR and %10111111;
+end;
+function TP6502.GetSTATUS_D: boolean;
+begin
+ Result := (SR and %00001000) <> 0;
+end;
+procedure TP6502.SetSTATUS_D(AValue: boolean);
+begin
+ if AVAlue then SR := SR or %00001000
+ else SR := SR and %11110111;
+end;
+function TP6502.GetSTATUS_I: boolean;
+begin
+ Result := (SR and %00000100) <> 0;
+end;
+procedure TP6502.SetSTATUS_I(AValue: boolean);
+begin
+ if AVAlue then SR := SR or %00000100
+ else SR := SR and %11111011;
+end;
+function TP6502.GetSTATUS_Z: boolean;
+begin
+ Result := (SR and %00000010) <> 0;
+end;
+procedure TP6502.SetSTATUS_Z(AValue: boolean);
+begin
+ if AVAlue then SR := SR or %00000010
+ else SR := SR and %11111101;
+end;
+function TP6502.GetSTATUS_C: boolean;
+begin
+ Result := (SR and %00000001) <> 0;
+end;
+procedure TP6502.SetSTATUS_C(AValue: boolean);
+begin
+ if AVAlue then SR := SR or %00000001
+ else SR := SR and %11111110;
+end;
+function TP6502.GetINTCON: byte;
+begin
+ Result := ram[$0B].dvalue;
+end;
+function TP6502.GetINTCON_GIE: boolean;
+begin
+ Result := (ram[$0B].dvalue and %10000000) <> 0;
+end;
+procedure TP6502.SetINTCON_GIE(AValue: boolean);
+begin
+ if AVAlue then ram[$0B].dvalue := ram[$0B].dvalue or %10000000
+ else ram[$0B].dvalue := ram[$0B].dvalue and %01111111;
+end;
+procedure TP6502.SetFRAM(value: byte);
+{Escribe en la RAM; en la direcci贸n global f_, el valor "value"
+Para determinar el valor real de la direcci贸n, se toma en cuenta los bits de STATUS}
+begin
+ ram[parIns].value := value;
+end;
+function TP6502.GetFRAM: byte;
+{Devuelve el valor de la RAM, de la posici贸n global f_.
+Para determinar el valor real de la direcci贸n, se toma en cuenta los bits de STATUS}
+begin
+ Result := ram[parIns].value;
+end;
+procedure TP6502.Decode(const opCode: word);
+{Decode the value of "opCode" and update:
+* "idIns" -> Instruction ID
+* "modIns" -> Address Mode
+If not found, returns "i_Inval" in "idIns".
+}
+var
+ i : TP6502Inst;
+ j : TP6502AddMode;
+ inst: TP6502Instruct;
+ iInfom: TInstructInform;
+begin
+ //Search the Opcode
+ for i := low(TP6502Inst) to high(TP6502Inst) do begin
+ inst := PIC16InstName[i];
+ for j := low(TP6502AddMode) to high(TP6502AddMode) do begin
+ iInfom := inst.instrInform[j];
+ if iInfom.Opcode = opCode then begin
+ idIns := i;
+ modIns := j;
+ exit;
+ end;
+ end;
+ end;
+ //Not found
+ idIns := i_Inval;
+end;
+function TP6502.DisassemblerAt(addr: word; out nBytesProc: byte;
+ useVarName: boolean): string;
+{Disassembler the instruction located at "addr". If the instruction is multibyte
+the intruction length, will be returned in "nBytesProc".
+
+Global variables used: "idIns", "modIns".
+"useVarName" -> Flag to use the name of the variable instead of only the address.
+ Valid only when a variAble name exists in his address.
+}
+var
+ nemo: String;
+ opCode, par1: Byte;
+ par2: word;
+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".
+ nemo := trim(PIC16InstName[idIns].name) + ' ';
+ case modIns of
+ aImplicit: begin
+ nBytesProc := 1; //No parameters needed
+ Result := nemo;
+ end;
+ aAcumulat: begin
+ nBytesProc := 1; //No parameters needed
+ Result := nemo;
+ end;
+ aImmediat: begin
+ Result := nemo + '#$'+IntToHex(par1,2);
+ nBytesProc := 2;
+ end;
+ aAbsolute: begin
+ nBytesProc := 3;
+ if addr+2>CPUMAXRAM-1 then exit('');
+ par2 := ram[addr+2].value<<8 + par1;
+ if useVarName and (ram[par2].name<>'') then begin
+ Result := nemo + ram[par2].name;
+ end else begin
+ Result := nemo + '$'+IntToHex(par2, 4);
+ end;
+ end;
+ aZeroPage: begin
+ if useVarName and (ram[par1].name<>'') then begin
+ Result := nemo + ram[par1].name;
+ end else begin
+ Result := nemo + '$'+IntToHex(par1, 2);
+ end;
+ nBytesProc := 2;
+ end;
+ aRelative: begin
+ 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;
+ aIndirect: begin
+ nBytesProc := 3;
+ if addr+2>CPUMAXRAM-1 then exit('');
+ par2 := ram[addr+2].value;
+ Result := nemo + '$('+IntToHex(par1 + par2*256, 4)+')';
+ end;
+ aAbsolutX: begin
+ nBytesProc := 3;
+ if addr+2>CPUMAXRAM-1 then exit('');
+ par2 := ram[addr+2].value;
+ Result := nemo + '$'+IntToHex(par1 + par2*256, 4)+',X';
+ end;
+ aAbsolutY: begin
+ nBytesProc := 3;
+ if addr+2>CPUMAXRAM-1 then exit('');
+ par2 := ram[addr+2].value;
+ Result := nemo + '$'+IntToHex(par1 + par2*256, 4)+',Y';
+ end;
+ aZeroPagX: begin
+ nBytesProc := 2;
+ Result := nemo + '$'+IntToHex(par1, 2)+',X';
+ end;
+ aZeroPagY: begin
+ nBytesProc := 2;
+ Result := nemo + '$'+IntToHex(par1, 2)+',Y';
+ end;
+ aIndirecX: begin
+ nBytesProc := 2;
+ Result := nemo + '$('+IntToHex(par1, 2)+',X)';
+ end;
+ aIndirecY: begin
+ nBytesProc := 2;
+ Result := nemo + '$('+IntToHex(par1, 2)+'),Y';
+ end;
+ end;
+end;
+function TP6502.CurInstruction: TP6502Inst;
+{Return the instruction pointed by PC, in this moment.}
+begin
+ Decode(ram[PC.W].value); //decode instruction
+ Result := idIns;
+end;
+procedure TP6502.Exec;
+{Execute the current instruction.}
+begin
+ Exec(PC.W);
+end;
+procedure TP6502.Exec(aPC: word);
+{Ejecuta la instruci贸n actual con direcci贸n "pc".
+Falta implementar las operaciones, cuando acceden al registro INDF, el Watchdog timer,
+los contadores, las interrupciones}
+var
+ opc: byte;
+ nCycles, nBytes, tmp, off: byte;
+ target , addr: word;
+ C_tmp: Boolean;
+ tmpRes: integer;
+begin
+ //Decodifica instrucci贸n
+ aPC := PC.W;
+ opc := ram[aPC].value;
+ Decode(opc); //Decode instruction
+ nCycles := PIC16InstName[idIns].instrInform[modIns].Cycles;
+ nBytes := PIC16InstName[idIns].instrInform[modIns].nBytes;
+ //Get Operand
+ case modIns of
+ aImmediat: addr := (aPC+1) and $FFFF;
+ aZeroPage: addr := ram[aPC+1].value;
+ aZeroPagX: addr := (ram[aPC+1].value + X) and $FF;
+ aAbsolute: addr := ram[aPC+1].value + 256*ram[aPC+2].value;
+ aAbsolutX: addr := (ram[aPC+1].value + 256*ram[aPC+2].value + X) and $FFFF;
+ aAbsolutY: addr := (ram[aPC+1].value + 256*ram[aPC+2].value + Y) and $FFFF;
+ aIndirecX: begin
+ tmp := (ram[aPC+1].value + X) and $FF;
+ addr := ram[tmp].value + 256*ram[tmp+1].value;
+ end;
+ aIndirecY: begin
+ tmp := ram[aPC+1].value;
+ addr := ram[tmp].value + 256*ram[tmp+1].value + Y;
+ end;
+ end;
+ //Execute
+ case idIns of
+ i_ADC: begin //add with carry
+ if STATUS_C then begin
+ tmpRes := W + ram[addr].value + 1;
+ end else begin
+ tmpRes := W + ram[addr].value;
+ end;
+ W := tmpRes and $FF;
+ STATUS_Z := W = 0;
+ STATUS_N := W > 127;
+ STATUS_C := tmpRes>255;
+ end;
+ i_AND: begin //and (with accumulator)
+ W := W and ram[addr].value;
+ STATUS_Z := W = 0;
+ STATUS_N := W > 127;
+ end;
+ i_ASL: begin //arithmetic shift left
+ if modIns = aAcumulat then tmp := W
+ else tmp := ram[addr].value;
+
+ STATUS_C := (tmp and $80) <> 0; //Read bit 7
+ tmp := tmp << 1;
+ STATUS_Z := tmp = 0;
+ STATUS_N := tmp > 127;
+
+ if modIns = aAcumulat then W := tmp
+ else ram[addr].value := tmp;
+ end;
+ i_BCC: begin //branch on carry clear
+ if not STATUS_C then begin
+ off := ram[aPC+1].value;
+ Inc(PC.W, nBytes); //Normal Increase PC
+ if off>127 then begin
+ PC.W := (PC.W + off - 256) and $FFFF;
+ end else begin
+ PC.W := (PC.W + off) and $FFFF;
+ end;
+ //Inc(PC.W, nBytes); //No apply
+ Inc(nClck, nCycles);
+ exit;
+ end;
+ end;
+ i_BCS: begin //branch on carry set
+ if STATUS_C then begin
+ off := ram[aPC+1].value;
+ Inc(PC.W, nBytes); //Normal Increase PC
+ if off>127 then begin
+ PC.w := (PC.W + off - 256) and $FFFF;
+ end else begin
+ PC.W := (PC.W + off) and $FFFF;
+ end;
+ //Inc(PC.W, nBytes); //No apply
+ Inc(nClck, nCycles);
+ exit;
+ end;
+ end;
+ i_BNE: begin //branch on not equal (zero clear)
+ if not STATUS_Z then begin
+ off := ram[aPC+1].value;
+ Inc(PC.W, nBytes); //Normal Increase PC
+ if off>127 then begin
+ PC.W := (PC.W + off - 256) and $FFFF;
+ end else begin
+ PC.W := (PC.W + off) and $FFFF;
+ end;
+ //Inc(PC.W, nBytes); //No apply
+ Inc(nClck, nCycles);
+ exit;
+ end;
+ end;
+ i_BEQ: begin //branch on equal (zero set)
+ if STATUS_Z then begin
+ off := ram[aPC+1].value;
+ Inc(PC.W, nBytes); //Normal Increase PC
+ if off>127 then begin
+ PC.w := (PC.W + off - 256) and $FFFF;
+ end else begin
+ PC.W := (PC.W + off) and $FFFF;
+ end;
+ //Inc(PC.W, nBytes); //No apply
+ Inc(nClck, nCycles);
+ exit;
+ end;
+ end;
+ i_BIT: begin //bit test
+ STATUS_N := (ram[addr].value AND $80) <> 0;
+ STATUS_V := (ram[addr].value AND $40) <> 0;
+ STATUS_Z := (W and ram[addr].value) <> 0;
+ end;
+ i_BPL: begin //branch on plus (negative clear)
+ if not STATUS_N then begin
+ off := ram[aPC+1].value;
+ Inc(PC.W, nBytes); //Normal Increase PC
+ if off>127 then begin
+ PC.W := (PC.W + off - 256) and $FFFF;
+ end else begin
+ PC.W := (PC.W + off) and $FFFF;
+ end;
+ //Inc(PC.W, nBytes); //No apply
+ Inc(nClck, nCycles);
+ exit;
+ end;
+ end;
+ i_BMI: begin //branch on minus (negative set)
+ if STATUS_N then begin
+ off := ram[aPC+1].value;
+ Inc(PC.W, nBytes); //Normal Increase PC
+ if off>127 then begin
+ PC.w := (PC.W + off - 256) and $FFFF;
+ end else begin
+ PC.W := (PC.W + off) and $FFFF;
+ end;
+ //Inc(PC.W, nBytes); //No apply
+ Inc(nClck, nCycles);
+ exit;
+ end;
+ end;
+ i_BRK: begin //break / interrupt
+ ram[$100 + SP].value := PC.L;
+ if SP = $00 then SP := $FF else dec(SP);
+ ram[$100 + SP].value := PC.H;
+ if SP = $00 then SP := $FF else dec(SP);
+ STATUS_I := true;
+ ram[$100 + SP].value := SR;
+ if SP = $00 then SP := $FF else dec(SP);
+ PC.L := ram[$FFFE].value;
+ PC.H := ram[$FFFF].value;
+ end;
+ i_BVC: begin //branch on overflow clear
+ if not STATUS_V then begin
+ off := ram[aPC+1].value;
+ Inc(PC.W, nBytes); //Normal Increase PC
+ if off>127 then begin
+ PC.W := (PC.W + off - 256) and $FFFF;
+ end else begin
+ PC.W := (PC.W + off) and $FFFF;
+ end;
+ //Inc(PC.W, nBytes); //No apply
+ Inc(nClck, nCycles);
+ exit;
+ end;
+ end;
+ i_BVS: begin //branch on overflow set
+ if STATUS_V then begin
+ off := ram[aPC+1].value;
+ Inc(PC.W, nBytes); //Normal Increase PC
+ if off>127 then begin
+ PC.w := (PC.W + off - 256) and $FFFF;
+ end else begin
+ PC.W := (PC.W + off) and $FFFF;
+ end;
+ //Inc(PC.W, nBytes); //No apply
+ Inc(nClck, nCycles);
+ exit;
+ end;
+ end;
+ i_CLC: STATUS_C := false; //clear carry
+ i_CLD: STATUS_D := false; //clear decimal
+ i_CLI: STATUS_I := false; //clear interrupt disable
+ i_CLV: STATUS_V := false; //clear overflow
+ i_CMP: begin //Compare (with accumulator)
+ tmp := ram[addr].value;
+ STATUS_Z := W = tmp;
+ STATUS_C := W >= tmp;
+ if W = tmp then begin
+ STATUS_N := false;
+ end else begin
+ STATUS_N := ((W-tmp) and $80) <> 0; //Copy bit 7
+ end;
+ end;
+ i_CPX: begin; //compare with X
+ tmp := ram[addr].value;
+ STATUS_Z := X = tmp;
+ STATUS_C := X >= tmp;
+ if X = tmp then begin
+ STATUS_N := false;
+ end else begin
+ STATUS_N := ((X-tmp) and $80) <> 0; //Copy bit 7
+ end;
+ end;
+ i_CPY: begin //compare with Y
+ tmp := ram[addr].value;
+ STATUS_Z := Y = tmp;
+ STATUS_C := Y >= tmp;
+ if Y = tmp then begin
+ STATUS_N := false;
+ end else begin
+ STATUS_N := ((Y-tmp) and $80) <> 0; //Copy bit 7
+ end;
+ end;
+ i_DEC: begin //decrement
+ tmp := (ram[addr].value - 1) and $FF;
+ ram[addr].value := tmp;
+ STATUS_Z := tmp = 0;
+ STATUS_N := tmp > 127;
+ end;
+ i_DEX: begin //decrement X
+ X := (X - 1) and $FF;
+ STATUS_Z := X = 0;
+ STATUS_N := X > 127;
+ end;
+ i_DEY: begin //decrement Y
+ Y := (Y - 1) and $FF;
+ STATUS_Z := Y = 0;
+ STATUS_N := Y > 127;
+ end;
+ i_EOR: begin //exclusive or (with accumulator)
+ W := W xor ram[addr].value;
+ STATUS_Z := W = 0;
+ STATUS_N := W > 127;
+ end;
+ i_INC: begin //increment
+ tmp := (ram[addr].value + 1) and $FF;
+ ram[addr].value := tmp;
+ STATUS_Z := tmp = 0;
+ STATUS_N := tmp > 127;
+ end;
+ i_INX: begin //increment X
+ X := (X + 1) and $FF;
+ STATUS_Z := X = 0;
+ STATUS_N := X > 127;
+ end;
+ i_INY: begin //increment Y
+ Y := (Y + 1) and $FF;
+ STATUS_Z := Y = 0;
+ STATUS_N := Y > 127;
+ end;
+ i_JMP: begin //jump
+ 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: begin //load accumulator
+ W := ram[addr].value;
+ STATUS_Z := W = 0;
+ STATUS_N := W > 127;
+ end;
+ i_LDX: begin //load X
+ X := ram[addr].value;
+ STATUS_Z := X = 0;
+ STATUS_N := X > 127;
+ end;
+ i_LDY: begin //load y
+ Y := ram[addr].value;
+ STATUS_Z := Y = 0;
+ STATUS_N := Y > 127;
+ end;
+ i_LSR: begin
+ STATUS_N := false;
+ if modIns = aAcumulat then tmp := W
+ else tmp := ram[addr].value;
+
+ STATUS_C := (tmp and $01) <> 0;
+ tmp := tmp >> 1;
+ STATUS_Z := tmp = 0;
+
+ if modIns = aAcumulat then W := tmp
+ else ram[addr].value := tmp;
+ end; //logical shift right
+ i_NOP: ; //no operation
+ i_ORA: begin //or with accumulator
+ W := W or ram[addr].value;
+ STATUS_Z := W = 0;
+ STATUS_N := W > 127;
+ end;
+ i_PHA: begin //push accumulator
+ ram[$100 + SP].value := W;
+ if SP = $00 then SP := $FF else dec(SP);
+ end;
+ i_PHP: begin //push processor status (SR)
+ ram[$100 + SP].value := STATUS;
+ if SP = $00 then SP := $FF else dec(SP);
+ end;
+ i_PLA: begin //pull accumulator
+ if SP = $FF then SP := $00 else inc(SP);
+ W := ram[$100 + SP].value;
+ end;
+ i_PLP: begin //pull processor status (SR)
+ if SP = $FF then SP := $00 else inc(SP);
+ SR := ram[$100 + SP].value;
+ end;
+ i_ROL: begin //rotate left
+ STATUS_N := false;
+ if modIns = aAcumulat then tmp := W
+ else tmp := ram[addr].value;
+
+ C_tmp := STATUS_C;
+ STATUS_C := (tmp and $80) <> 0; //Get bit 7
+ tmp := byte(tmp << 1);
+ if C_tmp then tmp := tmp or $01; //Insert bit 0
+ STATUS_Z := tmp = 0;
+ STATUS_N := tmp > 127;
+
+ if modIns = aAcumulat then W := tmp
+ else ram[addr].value := tmp;
+ end;
+ i_ROR: begin //rotate right
+ STATUS_N := false;
+ if modIns = aAcumulat then tmp := W
+ else tmp := ram[addr].value;
+
+ C_tmp := STATUS_C; //Save previos C
+ STATUS_C := (tmp and $01) <> 0; //Get bit 0
+ tmp := tmp >> 1;
+ if C_tmp then tmp := tmp or $80; //Insert bit 7
+ STATUS_Z := tmp = 0;
+ STATUS_N := tmp > 127;
+
+ if modIns = aAcumulat then W := tmp
+ else ram[addr].value := tmp;
+ end;
+ i_RTI: begin //return from interrupt
+ if SP = $FF then SP := $00 else inc(SP);
+ SR := ram[$100 + SP].value;
+ 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_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: begin //subtract with carry
+ if STATUS_C then begin
+ tmpRes := W - ram[addr].value - 1;
+ end else begin
+ tmpRes := W - ram[addr].value;
+ end;
+ W := tmpRes and $FF;
+ STATUS_Z := W = 0;
+ STATUS_N := W > 127;
+ STATUS_C := tmpRes<0;
+ end;
+ i_SEC: STATUS_C := true; //set carry
+ i_SED: STATUS_D := true; //set decimal
+ i_SEI: STATUS_I := true; //set interrupt disable
+ i_STA: begin //store accumulator
+ ram[addr].value := W;
+ end;
+ i_STX: begin //store X
+ ram[addr].value := X;
+ end;
+ i_STY: begin //store Y
+ ram[addr].value := Y;
+ end;
+ i_TAX: begin //transfer accumulator to X
+ X := W;
+ STATUS_Z := X = 0;
+ STATUS_N := X > 127;
+ end;
+ i_TAY: begin //transfer accumulator to Y
+ Y := W;
+ STATUS_Z := Y = 0;
+ STATUS_N := Y > 127;
+ end;
+ i_TSX: begin //transfer stack pointer to X
+ X := SP;
+ STATUS_Z := X = 0;
+ STATUS_N := X > 127;
+ end;
+ i_TXA: begin //transfer X to accumulator
+ W := X;
+ STATUS_Z := W = 0;
+ STATUS_N := W > 127;
+ end;
+ i_TXS: begin //transfer X to stack pointer
+ SP := X;
+ end;
+ i_TYA: begin //transfer Y to accumulator
+ W := Y;
+ STATUS_Z := W = 0;
+ STATUS_N := W > 127;
+ end;
+ i_Inval: begin
+ MsjError := 'Invalid Opcode';
+ end;
+ end;
+ //Increase counters
+ Inc(PC.W, nBytes);
+ Inc(nClck, nCycles);
+end;
+procedure TP6502.ExecTo(endAdd: word);
+{Ejecuta las instrucciones secuencialmente, desde la instrucci贸n actual, hasta que el
+contador del programa, sea igual a la direcci贸n "endAdd".}
+begin
+ //Hace una primera ejecuci贸n, sin verificar Breakpoints
+ Exec(PC.W);
+ //Ejecuta c铆clicamnente
+ while PC.W <> endAdd do begin
+ if ram[PC.W].breakPnt then begin
+ //Encontr贸 un BreakPoint, sale sin ejecutar esa instrucci贸n
+ if OnExecutionMsg<>nil then OnExecutionMsg('Stopped for breakpoint.');
+ exit;
+ end;
+ //Ejecuta
+ Exec(PC.W);
+ //Debe haber una forma de salir si es un lazo infinito
+ //if (nClck and $800000) = $800000 then begin
+ //end;
+ end;
+end;
+procedure TP6502.ExecStep;
+begin
+ if CurInstruction = i_JSR then begin
+ ExecTo(PC.W+3); //Ejecuta hasta la sgte. instrucci贸n, salta el JSR
+ end else begin
+ Exec;
+ end;
+end;
+procedure TP6502.ExecNCycles(nCyc: integer; out stopped: boolean);
+{Ejecuta el n煤mero de ciclos indicados, o hasta que se produzca alguna condici贸n
+externa, que puede ser:
+* Se encuentre un Punto de Interrupci贸n.
+* Se detecta la se帽al, de detenerse.
+* Se genere alg煤n error en la ejecuci贸n.
+* Se ejecuta la instrucci贸n i_SLEEP.
+la bandera "stopped", indica que se ha detendio la ejecuci贸n sin completar la cantidad
+de instrucciones requeridas.
+Normalmente Se ejecutar谩 el n煤mero de ciclos indicados, pero en algunos casos se
+ejecutar谩 un ciclo m谩s, debido a que algunas instrucciones toman dos ciclos.}
+var
+ clkEnd: Int64;
+ _pc: word;
+begin
+ clkEnd := nClck + nCyc; //Valor final del contador
+ while nClck < clkEnd do begin
+ _pc := PC.W;
+ if ram[_pc].breakPnt then begin
+ //Encontr贸 un BreakPoint, sale sin ejecutar esa instrucci贸n
+ if OnExecutionMsg<>nil then OnExecutionMsg('Stopped for breakpoint.');
+ stopped := true;
+ exit;
+ end;
+ if ram[_pc].used = ruUnused then begin
+ //Encontr贸 un BreakPoint, sale sin ejecutar esa instrucci贸n
+ if OnExecutionMsg<>nil then OnExecutionMsg('Stopped for executing unused code.');
+ stopped := true;
+ exit;
+ end;
+ if CommStop then begin
+ //Se detect贸 el comando STOP
+ if OnExecutionMsg<>nil then OnExecutionMsg('Stopped for STOP command.');
+ stopped := true;
+ exit;
+ end;
+ //Ejecuta
+ Exec(_pc);
+ end;
+ stopped := false;
+end;
+procedure TP6502.Reset(hard: boolean);
+//Reinicia el dipsoitivo
+var
+ i: Integer;
+begin
+ PC.W := 0;
+ W := 0;
+ SP := $FF; //Posici贸n inicial del puntero de pila
+ SR := %00000100; //I -> 1
+ nClck := 0; //Inicia contador de ciclos
+ CommStop := false; //Limpia bandera
+ if hard then begin
+ //Limpia solamente el valor inicial, no toca los otros campos
+ for i:=0 to high(ram) do begin
+ ram[i].dvalue := $00;
+ end;
+ end;
+end;
+function TP6502.ReadPC: dword;
+begin
+ Result := PC.W;
+end;
+procedure TP6502.WritePC(AValue: dword);
+begin
+ PC.W := AValue;
+end;
+//Funciones para la memoria RAM
+function TP6502.GetFreeByte(out addr: word): boolean;
+{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
+caso en que se quiera comaprtir la misma posici贸n para diversos variables.
+Si encuentra espacio, devuelve TRUE.}
+var
+ i: Integer;
+ maxRam: dword;
+begin
+ Result := false; //valor inicial
+ maxRam := CPUMAXRAM; //posici贸n m谩xima
+ //Verifica si hay zona de varaibles
+ if dataAddr1<>-1 then begin
+ //Busca en zona especial
+ for i:=dataAddr1 to dataAddr2 do begin
+ if (ram[i].state = cs_impleGPR) and (ram[i].used = ruUnused) then begin
+ //Esta direcci贸n est谩 libre
+ addr := i;
+ //Notar que la posici贸n de memoria puede estar mapeada.
+ exit(true); //indica que encontr贸 espacio
+ end;
+ end;
+ //No found. No more space available.
+ dataAddr1 := -1; //Deactivate
+ //Continue in the normal RAM
+ end;
+ //Busca en la zona normal
+ for i:=freeStart to maxRam-1 do begin
+ if (ram[i].state = cs_impleGPR) and (ram[i].used = ruUnused) then begin
+ //Esta direcci贸n est谩 libre
+ addr := i;
+ //Notar que la posici贸n de memoria puede estar mapeada.
+ exit(true); //indica que encontr贸 espacio
+ end;
+ end;
+end;
+function TP6502.GetFreeBytes(const size: integer; out addr: word): boolean;
+{Returns a free memory address of RAM to locate a block of the specified size (in bytes).
+ If found returns TRUE. }
+var
+ i: dword;
+ maxRam: dWord;
+begin
+ Result := false; //valor por defecto
+ if size=0 then begin
+ addr := 0;
+ exit(true);
+ end;
+ maxRam := CPUMAXRAM;
+ //Verifica si hay zona de varaibles
+ if dataAddr1<>-1 then begin
+ //Busca en zona especial
+ for i:=dataAddr1 to dataAddr2 do begin
+ if HaveConsecRAM(i, size, maxRam) then begin
+ //Encontr贸 del tama帽o buscado
+ addr := i;
+ exit(true);
+ end;
+ end;
+ //No found. No more space available.
+ dataAddr1 := -1; //Deactivate
+ //Continue in the normal RAM
+ end;
+ //Busca en la zona normal
+ for i:=freeStart to maxRam-1 do begin //verifica 1 a 1, por seguridad
+ if HaveConsecRAM(i, size, maxRam) then begin
+ //Encontr贸 del tama帽o buscado
+ addr := i;
+ exit(true);
+ end;
+ end;
+end;
+function TP6502.TotalMemRAM: integer;
+{Devuelve el total de memoria RAM disponible}
+var
+ i: Integer;
+begin
+ Result := 0;
+ for i := 0 to CPUMAXRAM - 1 do begin
+ if ram[i].Avail then begin
+ Result := Result + 1;
+ end;
+ end;
+end;
+function TP6502.UsedMemRAM: word;
+{Devuelve el total de memoria RAM usada}
+var
+ i: Integer;
+begin
+ Result := 0;
+ for i := 0 to CPUMAXRAM - 1 do begin
+ if ram[i].Avail and (ram[i].used<>ruUnused) then begin
+ //Notar que "AvailGPR" asegura que no se consideran registros maepados
+ Result := Result + 1;
+ end;
+ end;
+end;
+procedure TP6502.ExploreUsed(rutExplorRAM: TCPURutExplorRAM);
+{Genera un reporte de uso de RAM}
+var
+ i: Integer;
+begin
+ for i := 0 to CPUMAXRAM - 1 do begin
+ if ram[i].Avail and (ram[i].used<>ruUnused) then begin
+ rutExplorRAM(i, @ram[i]);
+ end;
+ end;
+end;
+function TP6502.ValidRAMaddr(addr: word): boolean;
+{Indica si la direcci贸n indicada es v谩lida dentro del hardware del CPU}
+begin
+ if addr > CPUMAXRAM then exit(false); //excede l铆mite
+ exit(true);
+end;
+procedure TP6502.DumpCodeAsm(lOut: TStrings;
+ incAdrr, incValues, incCom, incVarNam: boolean);
+{Desensambla las instrucciones grabadas en el PIC.
+ Se debe llamar despues de llamar a GenHex(), para que se actualicen las variables}
+var
+ i: Word;
+ lblLin, comLat, comLin, lin, opCode: String;
+ nBytes: byte;
+const
+ SPACEPAD = ' ';
+begin
+ //Se supone que minUsed y maxUsed, ya deben haber sido actualizados.
+ if incAdrr then begin
+ lOut.Add(SPACEPAD + ' ORG $' + IntToHex(minUsed, 4));
+ end else begin
+ lOut.Add(SPACEPAD + 'ORG $' + IntToHex(minUsed, 4));
+ end;
+ i := minUsed;
+ while i <= maxUsed do begin
+ //Lee comentarios y etiqueta
+ lblLin := ram[i].topLabel;
+ comLat := ram[i].sideComment;
+ comLin := ram[i].topComment;
+ //Verifica si es variable
+ if ram[i].used in [ruData, ruAbsData] then begin
+ //Escribe en forma de variable
+ if incAdrr then begin
+ if comLin<>'' then lOut.add(comLin);
+ //lOut.Add( PadRight(ram[i].name, Length(SPACEPAD)) + '$'+IntToHex(i,4) + ' DB ??');
+ lOut.Add( PadRight(ram[i].name, Length(SPACEPAD)) + '$'+IntToHex(i,4) + ' DB ' +
+ IntToHEx(ram[i].value,2) );
+ end else begin
+ //lOut.Add( PadRight(ram[i].name, Length(SPACEPAD)) + 'DB ??');
+ lOut.Add( PadRight(ram[i].name, Length(SPACEPAD)) + 'DB ' + IntToHEx(ram[i].value,2) );
+ end;
+ i := i + 1;
+ continue;
+ end;
+ //Escribe etiqueta al inicio de l铆nea
+ if lblLin<>'' then lOut.Add(lblLin+':');
+ //Escribe comentario al inicio de l铆nea
+ if incCom and (comLin<>'') then begin
+ lOut.Add(comLin);
+ end;
+ //Decodifica instrucci贸n
+ opCode := DisassemblerAt(i, nBytes, incVarNam); //Instrucci贸n
+ //Verificas si incluye direcci贸n f铆sica
+ lin := '';
+ if incAdrr then begin
+ //Agrega direcci贸n al inicio
+ lin := '$'+IntToHex(i,4) + ' ';
+ 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
+ if incCom then begin
+ lin := lin + ' ' + comLat;
+ end;
+ lOut.Add(SPACEPAD + lin);
+ i := i + nBytes; //Incrementa a siguiente instrucci贸n
+ end;
+end;
+procedure TP6502.GenHex(hexFile: string; startAddr: integer = -1);
+{Genera el archivo *.hex, a partir de los datos almacenados en la memoria RAM.
+Actualiza los campos, minUsed y maxUsed.}
+var
+ i: Integer;
+ f: file of byte;
+begin
+ hexLines.Clear; //Clear list
+ if startAddr = -1 then begin
+ //Find first and last byte used
+ minUsed := CPUMAXRAM;
+ maxUsed := 0;
+ for i := 0 to CPUMAXRAM-1 do begin
+ //if ram[i].used in [ruCode, ruData] then begin //Changed in versi贸n 0.7.1
+ if ram[i].used in [ruCode] then begin
+ if imaxUsed then maxUsed := i;
+ end;
+ end;
+ end else begin
+ //Find only last byte used
+ minUsed := startAddr;
+ maxUsed := 0;
+ for i := minUsed to CPUMAXRAM-1 do begin
+ //if ram[i].used in [ruCode, ruData] then begin //Changed in versi贸n 0.7.1
+ if ram[i].used in [ruCode] then begin
+ if i>maxUsed then maxUsed := i;
+ end;
+ end;
+ end;
+ //Genera archivo PRG
+ AssignFile(f, hexFile);
+ Rewrite(f);
+ Write(f, minUsed and $ff);
+ Write(f, (minUsed >> 8) and $ff);
+ for i := minUsed to maxUsed do begin //Llena buffer
+ Write(f, ram[i].value);
+ end;
+ close(f);
+end;
+constructor TP6502.Create;
+begin
+ inherited Create;
+ //Default hardware settings
+ Model := '6502';
+ CPUMAXRAM := $10000; //M谩x RAM memory
+ SetLength(ram, CPUMAXRAM);
+ //inicia una configuraci贸n com煤n
+ ClearMemRAM;
+ SetStatRAM($0000, $FFFF, cs_impleGPR);
+
+ //Estado inicial
+ iRam := 0; //posici贸n de inicio
+end;
+destructor TP6502.Destroy;
+begin
+ inherited Destroy;
+end;
+procedure InitTables;
+begin
+ ///////////////////////////////////////////////////////////////////
+ ////////////////// Set instructions information ///////////////////
+ // Based on the information from:
+ // http://www.masswerk.at/6502/6502_instruction_set.html
+ ///////////////////////////////////////////////////////////////////
+
+ ////////////////////////////// ADC ////////////////////////////////
+ PIC16InstName[i_ADC].name := 'ADC'; //Add Memory to Accumulator with Carry
+ PIC16InstName[i_ADC].AddAddressMode(aImmediat,$69,2,2,'');
+ PIC16InstName[i_ADC].AddAddressMode(aZeroPage,$65,2,3,'');
+ PIC16InstName[i_ADC].AddAddressMode(aZeroPagX,$75,2,4,'');
+ PIC16InstName[i_ADC].AddAddressMode(aAbsolute,$6D,3,4,'');
+ PIC16InstName[i_ADC].AddAddressMode(aAbsolutX,$7D,3,4,'*');
+ PIC16InstName[i_ADC].AddAddressMode(aAbsolutY,$79,3,4,'*');
+ PIC16InstName[i_ADC].AddAddressMode(aIndirecX,$61,2,6,'');
+ PIC16InstName[i_ADC].AddAddressMode(aIndirecY,$71,2,5,'*');
+ PIC16InstName[i_AND].name := 'AND'; //AND Memory with Accumulator
+ PIC16InstName[i_AND].AddAddressMode(aImmediat,$29,2,2,'');
+ PIC16InstName[i_AND].AddAddressMode(aZeroPage,$25,2,3,'');
+ PIC16InstName[i_AND].AddAddressMode(aZeroPagX,$35,2,4,'');
+ PIC16InstName[i_AND].AddAddressMode(aAbsolute,$2D,3,4,'');
+ PIC16InstName[i_AND].AddAddressMode(aAbsolutX,$3D,3,4,'*');
+ PIC16InstName[i_AND].AddAddressMode(aAbsolutY,$39,3,4,'*');
+ PIC16InstName[i_AND].AddAddressMode(aIndirecX,$21,2,6,'');
+ PIC16InstName[i_AND].AddAddressMode(aIndirecY,$31,2,5,'*');
+ PIC16InstName[i_ASL].name := 'ASL'; //Shift Left One Bit (MemoryorAccumulator)
+ PIC16InstName[i_ASL].AddAddressMode(aAcumulat,$0A,1,2,'');
+ PIC16InstName[i_ASL].AddAddressMode(aZeroPage,$06,2,5,'');
+ PIC16InstName[i_ASL].AddAddressMode(aZeroPagX,$16,2,6,'');
+ PIC16InstName[i_ASL].AddAddressMode(aAbsolute,$0E,3,6,'');
+ PIC16InstName[i_ASL].AddAddressMode(aAbsolutX,$1E,3,7,'');
+ PIC16InstName[i_BCC].name := 'BCC'; //Branch on Carry Clear
+ PIC16InstName[i_BCC].AddAddressMode(aRelative,$90,2,2,'**');
+ PIC16InstName[i_BCS].name := 'BCS'; //Branch on Carry Set
+ PIC16InstName[i_BCS].AddAddressMode(aRelative,$B0,2,2,'**');
+ PIC16InstName[i_BEQ].name := 'BEQ'; //Branch on Result Zero
+ PIC16InstName[i_BEQ].AddAddressMode(aRelative,$F0,2,2,'**');
+ PIC16InstName[i_BIT].name := 'BIT'; //Test Bits in Memory with Accumulator
+ PIC16InstName[i_BIT].AddAddressMode(aZeroPage,$24,2,3,'');
+ PIC16InstName[i_BIT].AddAddressMode(aAbsolute,$2C,3,4,'');
+ PIC16InstName[i_BMI].name := 'BMI'; //Branch on Result Minus
+ PIC16InstName[i_BMI].AddAddressMode(aRelative,$30,2,2,'**');
+ PIC16InstName[i_BNE].name := 'BNE'; //Branch on Result not Zero
+ PIC16InstName[i_BNE].AddAddressMode(aRelative,$D0,2,2,'**');
+ PIC16InstName[i_BPL].name := 'BPL'; //Branch on Result Plus
+ PIC16InstName[i_BPL].AddAddressMode(aRelative,$10,2,2,'**');
+ PIC16InstName[i_BRK].name := 'BRK'; //Force Break
+ PIC16InstName[i_BRK].AddAddressMode(aImplicit,$00,1,7,'');
+ PIC16InstName[i_BVC].name := 'BVC'; //Branch on Overflow Clear
+ PIC16InstName[i_BVC].AddAddressMode(aRelative,$50,2,2,'**');
+ PIC16InstName[i_BVS].name := 'BVS'; //Branch on Overflow Set
+ PIC16InstName[i_BVS].AddAddressMode(aRelative,$70,2,2,'**');
+ PIC16InstName[i_CLC].name := 'CLC'; //Clear Carry Flag
+ PIC16InstName[i_CLC].AddAddressMode(aImplicit,$18,1,2,'');
+ PIC16InstName[i_CLD].name := 'CLD'; //Clear Decimal Mode
+ PIC16InstName[i_CLD].AddAddressMode(aImplicit,$D8,1,2,'');
+ PIC16InstName[i_CLI].name := 'CLI'; //Clear Interrupt Disable Bit
+ PIC16InstName[i_CLI].AddAddressMode(aImplicit,$58,1,2,'');
+ PIC16InstName[i_CLV].name := 'CLV'; //Clear Overflow Flag
+ PIC16InstName[i_CLV].AddAddressMode(aImplicit,$B8,1,2,'');
+ PIC16InstName[i_CMP].name := 'CMP'; //Compare Memory with Accumulator
+ PIC16InstName[i_CMP].AddAddressMode(aImmediat,$C9,2,2,'');
+ PIC16InstName[i_CMP].AddAddressMode(aZeroPage,$C5,2,3,'');
+ PIC16InstName[i_CMP].AddAddressMode(aZeroPagX,$D5,2,4,'');
+ PIC16InstName[i_CMP].AddAddressMode(aAbsolute,$CD,3,4,'');
+ PIC16InstName[i_CMP].AddAddressMode(aAbsolutX,$DD,3,4,'*');
+ PIC16InstName[i_CMP].AddAddressMode(aAbsolutY,$D9,3,4,'*');
+ PIC16InstName[i_CMP].AddAddressMode(aIndirecX,$C1,2,6,'');
+ PIC16InstName[i_CMP].AddAddressMode(aIndirecY,$D1,2,5,'*');
+ PIC16InstName[i_CPX].name := 'CPX'; //Compare Memory and Index X
+ PIC16InstName[i_CPX].AddAddressMode(aImmediat,$E0,2,2,'');
+ PIC16InstName[i_CPX].AddAddressMode(aZeroPage,$E4,2,3,'');
+ PIC16InstName[i_CPX].AddAddressMode(aAbsolute,$EC,3,4,'');
+ PIC16InstName[i_CPY].name := 'CPY'; //Compare Memory and Index Y
+ PIC16InstName[i_CPY].AddAddressMode(aImmediat,$C0,2,2,'');
+ PIC16InstName[i_CPY].AddAddressMode(aZeroPage,$C4,2,3,'');
+ PIC16InstName[i_CPY].AddAddressMode(aAbsolute,$CC,3,4,'');
+ PIC16InstName[i_DEC].name := 'DEC'; //Decrement Memory by One
+ PIC16InstName[i_DEC].AddAddressMode(aZeroPage,$C6,2,5,'');
+ PIC16InstName[i_DEC].AddAddressMode(aZeroPagX,$D6,2,6,'');
+ PIC16InstName[i_DEC].AddAddressMode(aAbsolute,$CE,3,3,'');
+ PIC16InstName[i_DEC].AddAddressMode(aAbsolutX,$DE,3,7,'');
+ PIC16InstName[i_DEX].name := 'DEX'; //Decrement Index X by One
+ PIC16InstName[i_DEX].AddAddressMode(aImplicit,$CA,1,2,'');
+ PIC16InstName[i_DEY].name := 'DEY'; //Decrement Index Y by One
+ PIC16InstName[i_DEY].AddAddressMode(aImplicit,$88,1,2,'');
+ PIC16InstName[i_EOR].name := 'EOR'; //Exclusive-OR Memory with Accumulator
+ PIC16InstName[i_EOR].AddAddressMode(aImmediat,$49,2,2,'');
+ PIC16InstName[i_EOR].AddAddressMode(aZeroPage,$45,2,3,'');
+ PIC16InstName[i_EOR].AddAddressMode(aZeroPagX,$55,2,4,'');
+ PIC16InstName[i_EOR].AddAddressMode(aAbsolute,$4D,3,4,'');
+ PIC16InstName[i_EOR].AddAddressMode(aAbsolutX,$5D,3,4,'*');
+ PIC16InstName[i_EOR].AddAddressMode(aAbsolutY,$59,3,4,'*');
+ PIC16InstName[i_EOR].AddAddressMode(aIndirecX,$41,2,6,'');
+ PIC16InstName[i_EOR].AddAddressMode(aIndirecY,$51,2,5,'*');
+ PIC16InstName[i_INC].name := 'INC'; //Increment Memory by One
+ PIC16InstName[i_INC].AddAddressMode(aZeroPage,$E6,2,5,'');
+ PIC16InstName[i_INC].AddAddressMode(aZeroPagX,$F6,2,6,'');
+ PIC16InstName[i_INC].AddAddressMode(aAbsolute,$EE,3,6,'');
+ PIC16InstName[i_INC].AddAddressMode(aAbsolutX,$FE,3,7,'');
+ PIC16InstName[i_INX].name := 'INX'; //Increment Index X by One
+ PIC16InstName[i_INX].AddAddressMode(aImplicit,$E8,1,2,'');
+ PIC16InstName[i_INY].name := 'INY'; //Increment Index Y by One
+ PIC16InstName[i_INY].AddAddressMode(aImplicit,$C8,1,2,'');
+ PIC16InstName[i_JMP].name := 'JMP'; //Jump to New Location
+ PIC16InstName[i_JMP].AddAddressMode(aAbsolute,$4C,3,3,'');
+ PIC16InstName[i_JMP].AddAddressMode(aIndirect,$6C,3,5,'');
+ PIC16InstName[i_JSR].name := 'JSR'; //Jump to New Location Saving Return Address
+ PIC16InstName[i_JSR].AddAddressMode(aAbsolute,$20,3,6,'');
+ PIC16InstName[i_LDA].name := 'LDA'; //Load Accumulator with Memory
+ PIC16InstName[i_LDA].AddAddressMode(aImmediat,$A9,2,2,'');
+ PIC16InstName[i_LDA].AddAddressMode(aZeroPage,$A5,2,3,'');
+ PIC16InstName[i_LDA].AddAddressMode(aZeroPagX,$B5,2,4,'');
+ PIC16InstName[i_LDA].AddAddressMode(aAbsolute,$AD,3,4,'');
+ PIC16InstName[i_LDA].AddAddressMode(aAbsolutX,$BD,3,4,'*');
+ PIC16InstName[i_LDA].AddAddressMode(aAbsolutY,$B9,3,4,'*');
+ PIC16InstName[i_LDA].AddAddressMode(aIndirecX,$A1,2,6,'');
+ PIC16InstName[i_LDA].AddAddressMode(aIndirecY,$B1,2,5,'*');
+ PIC16InstName[i_LDX].name := 'LDX'; //Load Index X with Memory
+ PIC16InstName[i_LDX].AddAddressMode(aImmediat,$A2,2,2,'');
+ PIC16InstName[i_LDX].AddAddressMode(aZeroPage,$A6,2,3,'');
+ PIC16InstName[i_LDX].AddAddressMode(aZeroPagY,$B6,2,4,'');
+ PIC16InstName[i_LDX].AddAddressMode(aAbsolute,$AE,3,4,'');
+ PIC16InstName[i_LDX].AddAddressMode(aAbsolutY,$BE,3,4,'*');
+ PIC16InstName[i_LDY].name := 'LDY'; //Load Index Y with Memory
+ PIC16InstName[i_LDY].AddAddressMode(aImmediat,$A0,2,2,'');
+ PIC16InstName[i_LDY].AddAddressMode(aZeroPage,$A4,2,3,'');
+ PIC16InstName[i_LDY].AddAddressMode(aZeroPagX,$B4,2,4,'');
+ PIC16InstName[i_LDY].AddAddressMode(aAbsolute,$AC,3,4,'');
+ PIC16InstName[i_LDY].AddAddressMode(aAbsolutX,$BC,3,4,'*');
+ PIC16InstName[i_LSR].name := 'LSR'; //Shift One Bit Right (Memory orAccumulator)
+ PIC16InstName[i_LSR].AddAddressMode(aAcumulat,$4A,1,2,'');
+ PIC16InstName[i_LSR].AddAddressMode(aZeroPage,$46,2,5,'');
+ PIC16InstName[i_LSR].AddAddressMode(aZeroPagX,$56,2,6,'');
+ PIC16InstName[i_LSR].AddAddressMode(aAbsolute,$4E,3,6,'');
+ PIC16InstName[i_LSR].AddAddressMode(aAbsolutX,$5E,3,7,'');
+ PIC16InstName[i_NOP].name := 'NOP'; //No Operation
+ PIC16InstName[i_NOP].AddAddressMode(aImplicit,$EA,1,2,'');
+ PIC16InstName[i_ORA].name := 'ORA'; //OR Memory with Accumulator
+ PIC16InstName[i_ORA].AddAddressMode(aImmediat,$09,2,2,'');
+ PIC16InstName[i_ORA].AddAddressMode(aZeroPage,$05,2,3,'');
+ PIC16InstName[i_ORA].AddAddressMode(aZeroPagX,$15,2,4,'');
+ PIC16InstName[i_ORA].AddAddressMode(aAbsolute,$0D,3,4,'');
+ PIC16InstName[i_ORA].AddAddressMode(aAbsolutX,$1D,3,4,'*');
+ PIC16InstName[i_ORA].AddAddressMode(aAbsolutY,$19,3,4,'*');
+ PIC16InstName[i_ORA].AddAddressMode(aIndirecX,$01,2,6,'');
+ PIC16InstName[i_ORA].AddAddressMode(aIndirecY,$11,2,5,'*');
+ PIC16InstName[i_PHA].name := 'PHA'; //Push Accumulator on Stack
+ PIC16InstName[i_PHA].AddAddressMode(aImplicit,$48,1,3,'');
+ PIC16InstName[i_PHP].name := 'PHP'; //Push Processor Status on Stack
+ PIC16InstName[i_PHP].AddAddressMode(aImplicit,$08,1,3,'');
+ PIC16InstName[i_PLA].name := 'PLA'; //Pull Accumulator from Stack
+ PIC16InstName[i_PLA].AddAddressMode(aImplicit,$68,1,4,'');
+ PIC16InstName[i_PLP].name := 'PLP'; //Pull Processor Status fromStack
+ PIC16InstName[i_PLP].AddAddressMode(aImplicit,$28,1,4,'');
+ PIC16InstName[i_ROL].name := 'ROL'; //Rotate One Bit Left (Memory orAccumulator)
+ PIC16InstName[i_ROL].AddAddressMode(aAcumulat,$2A,1,2,'');
+ PIC16InstName[i_ROL].AddAddressMode(aZeroPage,$26,2,5,'');
+ PIC16InstName[i_ROL].AddAddressMode(aZeroPagX,$36,2,6,'');
+ PIC16InstName[i_ROL].AddAddressMode(aAbsolute,$2E,3,6,'');
+ PIC16InstName[i_ROL].AddAddressMode(aAbsolutX,$3E,3,7,'');
+ PIC16InstName[i_ROR].name := 'ROR'; //Rotate One Bit Right (Memory or Accumulator)
+ PIC16InstName[i_ROR].AddAddressMode(aAcumulat,$6A,1,2,'');
+ PIC16InstName[i_ROR].AddAddressMode(aZeroPage,$66,2,5,'');
+ PIC16InstName[i_ROR].AddAddressMode(aZeroPagX,$76,2,6,'');
+ PIC16InstName[i_ROR].AddAddressMode(aAbsolute,$6E,3,6,'');
+ PIC16InstName[i_ROR].AddAddressMode(aAbsolutX,$7E,3,7,'');
+ PIC16InstName[i_RTI].name := 'RTI'; //Return from Interrupt
+ PIC16InstName[i_RTI].AddAddressMode(aImplicit,$40,1,6,'');
+ PIC16InstName[i_RTS].name := 'RTS'; //Return from Subroutine
+ PIC16InstName[i_RTS].AddAddressMode(aImplicit,$60,1,6,'');
+ PIC16InstName[i_SBC].name := 'SBC'; //Subtract Memory from Accumulator withBorrow
+ PIC16InstName[i_SBC].AddAddressMode(aImmediat,$E9,2,2,'');
+ PIC16InstName[i_SBC].AddAddressMode(aZeroPage,$E5,2,3,'');
+ PIC16InstName[i_SBC].AddAddressMode(aZeroPagX,$F5,2,4,'');
+ PIC16InstName[i_SBC].AddAddressMode(aAbsolute,$ED,3,4,'');
+ PIC16InstName[i_SBC].AddAddressMode(aAbsolutX,$FD,3,4,'*');
+ PIC16InstName[i_SBC].AddAddressMode(aAbsolutY,$F9,3,4,'*');
+ PIC16InstName[i_SBC].AddAddressMode(aIndirecX,$E1,2,6,'');
+ PIC16InstName[i_SBC].AddAddressMode(aIndirecY,$F1,2,5,'*');
+ PIC16InstName[i_SEC].name := 'SEC'; //Set Carry Flag
+ PIC16InstName[i_SEC].AddAddressMode(aImplicit,$38,1,2,'');
+ PIC16InstName[i_SED].name := 'SED'; //Set Decimal Flag
+ PIC16InstName[i_SED].AddAddressMode(aImplicit,$F8,1,2,'');
+ PIC16InstName[i_SEI].name := 'SEI'; //Set Interrupt Disable Status
+ PIC16InstName[i_SEI].AddAddressMode(aImplicit,$78,1,2,'');
+ PIC16InstName[i_STA].name := 'STA'; //Store Accumulator in Memory
+ PIC16InstName[i_STA].AddAddressMode(aZeroPage,$85,2,3,'');
+ PIC16InstName[i_STA].AddAddressMode(aZeroPagX,$95,2,4,'');
+ PIC16InstName[i_STA].AddAddressMode(aAbsolute,$8D,3,4,'');
+ PIC16InstName[i_STA].AddAddressMode(aAbsolutX,$9D,3,5,'');
+ PIC16InstName[i_STA].AddAddressMode(aAbsolutY,$99,3,5,'');
+ PIC16InstName[i_STA].AddAddressMode(aIndirecX,$81,2,6,'');
+ PIC16InstName[i_STA].AddAddressMode(aIndirecY,$91,2,6,'');
+ PIC16InstName[i_STX].name := 'STX'; //Store Index X in Memory
+ PIC16InstName[i_STX].AddAddressMode(aZeroPage,$86,2,3,'');
+ PIC16InstName[i_STX].AddAddressMode(aZeroPagY,$96,2,4,'');
+ PIC16InstName[i_STX].AddAddressMode(aAbsolute,$8E,3,4,'');
+ PIC16InstName[i_STY].name := 'STY'; //Sore Index Y in Memory
+ PIC16InstName[i_STY].AddAddressMode(aZeroPage,$84,2,3,'');
+ PIC16InstName[i_STY].AddAddressMode(aZeroPagX,$94,2,4,'');
+ PIC16InstName[i_STY].AddAddressMode(aAbsolute,$8C,3,4,'');
+ PIC16InstName[i_TAX].name := 'TAX'; //Transfer Accumulator to IndexX
+ PIC16InstName[i_TAX].AddAddressMode(aImplicit,$AA,1,2,'');
+ PIC16InstName[i_TAY].name := 'TAY'; //Transfer Accumulator to IndexY
+ PIC16InstName[i_TAY].AddAddressMode(aImplicit,$A8,1,2,'');
+ PIC16InstName[i_TSX].name := 'TSX'; //Transfer Stack Pointer toIndex X
+ PIC16InstName[i_TSX].AddAddressMode(aImplicit,$BA,1,2,'');
+ PIC16InstName[i_TXA].name := 'TXA'; //Transfer Index X to Accumulator
+ PIC16InstName[i_TXA].AddAddressMode(aImplicit,$8A,1,2,'');
+ PIC16InstName[i_TXS].name := 'TXS'; //Transfer Index X to StackRegister
+ PIC16InstName[i_TXS].AddAddressMode(aImplicit,$9A,1,2,'');
+ PIC16InstName[i_TYA].name := 'TYA'; //Transfer Index Y to Accumulator
+ PIC16InstName[i_TYA].AddAddressMode(aImplicit,$98,1,2,'');
+
+ PIC16InstName[i_Inval].name := 'Inv';
+
+
+end;
+initialization
+ InitTables;
+end. //1550
diff --git a/README.md b/README.md
index aa57f43..8193bce 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,10 @@
-# P65Utils
-Utilities for the CPU 6502
+# P65Utils 0.5
+
+Pascal utilities for the CPU 6502.
+
+This utilities are used by the compiler P65Pas: https://github.com/t-edson/P65Pas
+
+Content:
+- CPUCore.pas -> Unit with basic definitions of 6502 CPU families.
+- P6502utils.pas -> Unit with Pascal definitions for the CPU 6502.
+- P65C02utils.pas -> Unit with Pascal definitions for the CPU 65C02.
\ No newline at end of file