mirror of https://github.com/t-edson/P65Utils.git
Add files via upload
This commit is contained in:
parent
1d05a351f9
commit
729875617f
166
CPUCore.pas
166
CPUCore.pas
|
@ -52,7 +52,8 @@ type //Models for RAM memory
|
|||
state : TCPUCellState; //Status of the cell
|
||||
property value: byte read Getvalue write Setvalue;
|
||||
property dvalue: byte read Fvalue write Fvalue; //Direct access to "Fvalue".
|
||||
function Avail: boolean;
|
||||
function Avail: boolean; //RAM implemented to use in programs
|
||||
function Free: boolean; //RAM implemented and unused
|
||||
public //Campos para deputación
|
||||
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}
|
||||
|
@ -76,8 +77,10 @@ type //Models for RAM memory
|
|||
type
|
||||
|
||||
{ TCPUCore }
|
||||
{Abcestor of all 8 bits PIC cores}
|
||||
{Abcestor of all 8 bits CPU cores}
|
||||
TCPUCore = class
|
||||
private
|
||||
function GetTokAddress(var str: string; delimiter: char): word;
|
||||
public //Limits
|
||||
{This variables are set just one time. So they work as constant.}
|
||||
CPUMAXRAM: dword; //Max virtual RAM used by the CPU
|
||||
|
@ -91,7 +94,7 @@ type
|
|||
nClck : Int64; //Contador de ciclos de reloj
|
||||
CommStop: boolean; //Bandera para detener la ejecución
|
||||
OnExecutionMsg: procedure(message: string) of object; //Genera mensaje en ejecución
|
||||
protected //Generation of HEX files
|
||||
protected //Generation of PRG files
|
||||
minUsed : dword; //Dirección menor de la ROM usada
|
||||
maxUsed : dword; //Dirección mayor de la ROM usdas
|
||||
hexLines : TStringList; //Uusado para crear archivo *.hex
|
||||
|
@ -101,6 +104,9 @@ type
|
|||
function DisassemblerAt(addr: word; out nBytesProc: byte; useVarName: boolean
|
||||
): string; virtual; abstract; //Desensambla la instrucción actual
|
||||
public //RAM memory functions
|
||||
hasDataAdrr: integer; //Flag/index to indicate a Data block has defined.
|
||||
dataAddr1: integer; //Start address for Data variables (-1 if not used)
|
||||
dataAddr2: integer;
|
||||
procedure ClearMemRAM;
|
||||
procedure DisableAllRAM;
|
||||
procedure SetStatRAM(i1, i2: word; status0: TCPUCellState);
|
||||
|
@ -110,7 +116,7 @@ type
|
|||
procedure UseConsecRAM(const i, n: word); //Ocupa "n" bytes en la posición "i"
|
||||
procedure SetSharedUnused;
|
||||
procedure SetSharedUsed;
|
||||
public //ram memory functions
|
||||
public //RAM memory functions
|
||||
function UsedMemRAM: word; //devuelve el total de memoria ram usada
|
||||
public //RAM name managment
|
||||
function NameRAM(const addr: word): string;
|
||||
|
@ -128,6 +134,7 @@ type
|
|||
function ReadPC: dword; virtual; abstract; //Defined DWORD to cover the 18F PC register
|
||||
procedure WritePC(AValue: dword); virtual; abstract;
|
||||
public //Others
|
||||
|
||||
procedure addTopLabel(lbl: string); //Add a comment to the ASM code
|
||||
procedure addTopComm(comm: string; replace: boolean = true); //Add a comment to the ASM code
|
||||
procedure addSideComm(comm: string; before: boolean); //Add lateral comment to the ASM code
|
||||
|
@ -149,29 +156,70 @@ begin
|
|||
Fvalue := AValue;
|
||||
end;
|
||||
function TCPURamCell.Avail: boolean;
|
||||
{Indica si el registro es una dirección disponible en la memoria RAM.}
|
||||
{Indicates if the RAM cell is available for programmer.}
|
||||
begin
|
||||
Result := (state = cs_impleGPR);
|
||||
end;
|
||||
function TCPURamCell.Free: boolean;
|
||||
begin
|
||||
Result := (state = cs_impleGPR) and (used = ruUnused);
|
||||
end;
|
||||
function TCPUCore.GetTokAddress(var str: string; delimiter: char): word;
|
||||
{Extract a number (address) from a string and delete until de delimiter.
|
||||
If delimiter is #0, it's consider all the text.
|
||||
If fail update the variable "MsjError".}
|
||||
var
|
||||
p: SizeInt;
|
||||
n: Longint;
|
||||
begin
|
||||
if delimiter=#0 then begin
|
||||
//Until the end of line
|
||||
p := length(str) + 1;
|
||||
end else begin
|
||||
//Until delimiter
|
||||
p := pos(delimiter, str);
|
||||
if p = 0 then begin
|
||||
MsjError := 'Expected "'+delimiter+'".';
|
||||
exit(0);
|
||||
end;
|
||||
end;
|
||||
//Have delimiter. Get number
|
||||
if not TryStrToInt('$'+copy(str,1,p-1), n) then begin
|
||||
MsjError := 'Wrong address.';
|
||||
exit(0);
|
||||
end;
|
||||
delete(str, 1, p); //delete number and delimiter
|
||||
if n<0 then begin
|
||||
MsjError := 'Address cannot be negative.';
|
||||
exit(0);
|
||||
end;
|
||||
if n>$FFFF then begin
|
||||
MsjError := 'Address cannot be greater than $FFFF.';
|
||||
exit(0);
|
||||
end;
|
||||
exit(n);
|
||||
end;
|
||||
|
||||
{ TCPUCore }
|
||||
//RAM memory functions
|
||||
procedure TCPUCore.ClearMemRAM;
|
||||
{Limpia el contenido de la memoria}
|
||||
{Clear content of RAM. Doesn't change the state.}
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
for i:=0 to high(ram) do begin
|
||||
ram[i].dvalue := $00;
|
||||
ram[i].used := ruUnused;
|
||||
ram[i].name:='';
|
||||
ram[i].shared := false;
|
||||
ram[i].breakPnt := false;
|
||||
ram[i].topLabel := '';
|
||||
ram[i].dvalue := $00;
|
||||
ram[i].used := ruUnused;
|
||||
ram[i].name :='';
|
||||
ram[i].shared := false;
|
||||
ram[i].breakPnt := false;
|
||||
ram[i].topLabel := '';
|
||||
ram[i].sideComment:= '';
|
||||
ram[i].topComment := '';
|
||||
ram[i].idFile := -1; //Indica no inicializado
|
||||
// ram[i].state := cs_unimplem; //por defecto se considera no implementado
|
||||
ram[i].topComment:= '';
|
||||
ram[i].idFile := -1; //Not initialized.
|
||||
{Don't change the implementation. Because "state" must be defined just once at the
|
||||
First Pass when processing $CLEAR_STATE_RAM and $SET_STATE_RAM }
|
||||
// ram[i].state := cs_impleGPR;
|
||||
end;
|
||||
end;
|
||||
procedure TCPUCore.DisableAllRAM;
|
||||
|
@ -196,20 +244,20 @@ begin
|
|||
end;
|
||||
end;
|
||||
function TCPUCore.SetStatRAMCom(strDef: string): boolean;
|
||||
{Define el estado de la memoria RAM, usando una cadena de definición.
|
||||
La cadena de definición, tiene el formato:
|
||||
<comando 1>, <comando 2>, ...
|
||||
Cada comando, tiene el formato:
|
||||
<dirIni>-<dirFin>:<estado de memoria>
|
||||
Un ejemplo de cadena de definición, es:
|
||||
'000-01F:IMP, 020-07F:NIM'
|
||||
Si hay error, devuelve FALSE, y el mensaje de error en MsjError.
|
||||
{Define the RAM state using a Definitions string.
|
||||
Definitions string have the format:
|
||||
<command 1>, <command 2>, ...
|
||||
Each command have the format:
|
||||
<addStart>-<addEnd>:<memory state>
|
||||
One example for Definitions string, is:
|
||||
'0000-01FF:SFR, 8000-FFFF:NIM'
|
||||
If error ocurrs, return FALSE, and the error messaje in MsjError.
|
||||
}
|
||||
var
|
||||
coms: TStringList;
|
||||
add1, add2: longint;
|
||||
state: TCPUCellState;
|
||||
staMem, com, str: String;
|
||||
com, str: String;
|
||||
begin
|
||||
Result := true;
|
||||
coms:= TStringList.Create;
|
||||
|
@ -219,33 +267,24 @@ begin
|
|||
for str in coms do begin
|
||||
com := UpCase(trim(str));
|
||||
if com='' then continue;
|
||||
if length(com)<>11 then begin
|
||||
MsjError := 'Memory definition syntax error: Bad string size.';
|
||||
//Find Address1
|
||||
add1 := GetTokAddress(com, '-');
|
||||
if MsjError<>'' then begin
|
||||
MsjError := 'Memory definition syntax error: ' + MsjError;
|
||||
exit(false);
|
||||
end;
|
||||
if com[4] <> '-' then begin
|
||||
MsjError := 'Memory definition syntax error: Expected "-".';
|
||||
//Find Address1
|
||||
add2 := GetTokAddress(com, ':');
|
||||
if MsjError<>'' then begin
|
||||
MsjError := 'Memory definition syntax error: ' + MsjError;
|
||||
exit(false);
|
||||
end;
|
||||
if com[8] <> ':' then begin
|
||||
MsjError := 'Memory definition syntax error: Expected ":".';
|
||||
exit(false);
|
||||
end;
|
||||
//Debe tener el formato pedido
|
||||
if not TryStrToInt('$'+copy(com,1,3), add1) then begin
|
||||
MsjError := 'Memory definition syntax error: Wrong address.';
|
||||
exit(false);
|
||||
end;
|
||||
if not TryStrToInt('$'+copy(com,5,3), add2) then begin
|
||||
MsjError := 'Memory definition syntax error: Wrong address.';
|
||||
exit(false);
|
||||
end;
|
||||
staMem := copy(com, 9, 3);
|
||||
case staMem of
|
||||
'IMP': state := cs_impleGPR;
|
||||
case copy(com,1,3) of
|
||||
'SFR': state := cs_impleSFR;
|
||||
'GPR': state := cs_impleGPR;
|
||||
'NIM': state := cs_unimplem;
|
||||
else
|
||||
MsjError := 'Memory definition syntax error: Expected IMP or NIM';
|
||||
MsjError := 'Memory definition syntax error: Expected SFR, GPR or NIM';
|
||||
exit(false);
|
||||
end;
|
||||
//Ya se tienen los parámetros, para definir la memoria
|
||||
|
@ -256,8 +295,42 @@ begin
|
|||
end;
|
||||
end;
|
||||
function TCPUCore.SetDataAddr(strDef: string): boolean;
|
||||
{Define primary address to be used for allocating variables.
|
||||
Definitions string have the format:
|
||||
<command 1>, <command 2>, ...
|
||||
Each command have the format:
|
||||
<addStart>-<addEnd>:<memory state>
|
||||
One example for Definitions string, is:
|
||||
'00F0-00FF'
|
||||
If error ocurrs, return FALSE, and the error message in MsjError.
|
||||
}
|
||||
var
|
||||
add1, add2: longint;
|
||||
com: String;
|
||||
begin
|
||||
Result := true;
|
||||
|
||||
com := UpCase(trim(strDef));
|
||||
if com='' then begin
|
||||
hasDataAdrr := -1; //Disable
|
||||
exit;
|
||||
end;
|
||||
//Find Address1
|
||||
add1 := GetTokAddress(com, '-');
|
||||
if MsjError<>'' then begin
|
||||
MsjError := 'Memory definition syntax error: ' + MsjError;
|
||||
exit(false);
|
||||
end;
|
||||
//Find Address1
|
||||
add2 := GetTokAddress(com, #0);
|
||||
if MsjError<>'' then begin
|
||||
MsjError := 'Memory definition syntax error: ' + MsjError;
|
||||
exit(false);
|
||||
end;
|
||||
//Ya se tienen los parámetros, para definir la memoria
|
||||
hasDataAdrr := add1; //Set flag
|
||||
dataAddr1 := add1; //Save
|
||||
dataAddr2 := add2; //Save end
|
||||
end;
|
||||
function TCPUCore.HaveConsecRAM(const i, n: word; maxRam: dword): boolean;
|
||||
{Indica si hay "n" bytes consecutivos libres en la posicióm "i", en RAM.
|
||||
|
@ -270,7 +343,7 @@ begin
|
|||
c := 0;
|
||||
j := i;
|
||||
while (j<=maxRam) and (c<n) do begin
|
||||
if (ram[j].state <> cs_impleGPR) or (ram[j].used<>ruUnused) then exit;
|
||||
if not ram[j].Free then exit;
|
||||
inc(c); //verifica siguiente
|
||||
inc(j);
|
||||
end;
|
||||
|
@ -393,6 +466,7 @@ end;
|
|||
//Initialization
|
||||
constructor TCPUCore.Create;
|
||||
begin
|
||||
hasDataAdrr := -1; //Disable
|
||||
hexLines := TStringList.Create;
|
||||
frequen := 1000000; //4MHz
|
||||
end;
|
||||
|
|
|
@ -190,6 +190,7 @@ type
|
|||
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
|
||||
|
@ -206,7 +207,7 @@ type
|
|||
public //Aditional methods
|
||||
function FindOpcode(Op: string): TP6502Inst; //Find Opcode
|
||||
function IsRelJump(idInst: TP6502Inst): boolean; //Idnetify realtive jumps Opcodes
|
||||
procedure GenHex(hexFile: string); //genera un archivo hex
|
||||
procedure GenHex(hexFile: string; startAddr: integer = - 1); //genera un archivo hex
|
||||
procedure DumpCodeAsm(lOut: TStrings; incAdrr, incValues, incCom,
|
||||
incVarNam: boolean);
|
||||
public //Initialization
|
||||
|
@ -1151,18 +1152,28 @@ var
|
|||
begin
|
||||
Result := false; //valor inicial
|
||||
maxRam := CPUMAXRAM; //posición máxima
|
||||
//Realmente debería explorar solo hasta la dirección implementada, por eficiencia
|
||||
for i:=iRam to maxRam-1 do begin
|
||||
//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
|
||||
// ram[i].used := ruData; //marca como usado para variable
|
||||
// if shared then begin
|
||||
// ram[i].shared := true; //Marca como compartido
|
||||
// end;
|
||||
addr := i;
|
||||
//Notar que la posición de memoria puede estar mapeada.
|
||||
Result := true; //indica que encontró espacio
|
||||
exit;
|
||||
exit(true); //indica que encontró espacio
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
@ -1179,10 +1190,24 @@ begin
|
|||
exit(true);
|
||||
end;
|
||||
maxRam := CPUMAXRAM;
|
||||
for i:=iRam to maxRam-1 do begin //verifica 1 a 1, por seguridad
|
||||
//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
|
||||
//UseConsecRAM(i, size); //marca como usado
|
||||
//Encontró del tamaño buscado
|
||||
addr := i;
|
||||
exit(true);
|
||||
end;
|
||||
|
@ -1304,22 +1329,34 @@ begin
|
|||
i := i + nBytes; //Incrementa a siguiente instrucción
|
||||
end;
|
||||
end;
|
||||
procedure TP6502.GenHex(hexFile: string);
|
||||
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; //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 in [ruCode, ruData] then begin
|
||||
if i<minUsed then minUsed := i;
|
||||
if i>maxUsed then maxUsed := i;
|
||||
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 i<minUsed then minUsed := i;
|
||||
if i>maxUsed 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
|
||||
|
@ -1341,7 +1378,7 @@ begin
|
|||
SetLength(ram, CPUMAXRAM);
|
||||
//inicia una configuración común
|
||||
ClearMemRAM;
|
||||
SetStatRAM($020, $04F, cs_impleGPR);
|
||||
SetStatRAM($0000, $FFFF, cs_impleGPR);
|
||||
|
||||
//Estado inicial
|
||||
iRam := 0; //posición de inicio
|
||||
|
|
Loading…
Reference in New Issue