From 8b36a3178c195f3161762d3813047f4d71ecf725 Mon Sep 17 00:00:00 2001 From: Tito Hinostroza Date: Thu, 9 Aug 2018 22:04:37 -0500 Subject: [PATCH] Add files via upload --- CPUCore.pas | 555 ++++++++++++ Cambios.txt | 7 +- MiniAssembler/project1.exe.hex | 4 + MiniAssembler/project1.lpi | 80 ++ MiniAssembler/project1.lpr | 21 + MiniAssembler/project1.lps | 148 ++++ MiniAssembler/project1.res | Bin 0 -> 138932 bytes MiniAssembler/unit1.lfm | 55 ++ MiniAssembler/unit1.pas | 186 ++++ P6502utils.pas | 1446 ++++++++++++++++++++++++++++++++ 10 files changed, 2501 insertions(+), 1 deletion(-) create mode 100644 CPUCore.pas create mode 100644 MiniAssembler/project1.exe.hex create mode 100644 MiniAssembler/project1.lpi create mode 100644 MiniAssembler/project1.lpr create mode 100644 MiniAssembler/project1.lps create mode 100644 MiniAssembler/project1.res create mode 100644 MiniAssembler/unit1.lfm create mode 100644 MiniAssembler/unit1.pas create mode 100644 P6502utils.pas diff --git a/CPUCore.pas b/CPUCore.pas new file mode 100644 index 0000000..252dd38 --- /dev/null +++ b/CPUCore.pas @@ -0,0 +1,555 @@ +{PICCore + +Contains basic definitions applicable to all PIC microcontroller Cores + Created by Tito Hinostroza 28/04/2018 +} +unit CPUCore; +{$mode objfpc}{$H+} +interface +uses + Classes, SysUtils, LCLProc; +const + PIC_MAX_PINES = 64; //Max. number of pines for the package +type + //Union to access bytes of a word + TWordRec = record + case byte of + 1 : (W : Word); + {$IFDEF ENDIAN_LITTLE} + 2 : (L, H: Byte); + {$ELSE} + 2 : (H, L: Byte); + {$ENDIF} + end; + + TCPUCellState = ( + cs_impleGPR, //Implemented. Can be used. + cs_unimplem //Not implemented. + ); + + TCPUPinType = ( + pptVcc, //Alimentación + pptGND, //Tierra + pptControl,//Pin de control + pptPort, //Puerto Entrada/Salida + pptUnused //Pin no usado + ); + + { TCPUPin } + //Model for a phisycal pin of the PIC + TCPUPin = object + nam: string; //Eqtiueta o nombre + typ: TCPUPinType; //Tipo de pin + add: word; //Dirección en RAM + bit: byte; //Bit en RAM + function GetLabel: string; + end; + TCPUPinPtr = ^TCPUPin; + +type //Models for RAM memory + + { TCPURamCell } + {Modela a una dirección lógica de la memoria RAM. Se ha taratdo de hacer una + definición eficiente de esta estructura para facilitar la implementación de + simuladores en tiempo real. Podemos usar un tamaño mediano para este registro, + porque no esperamos tener muchas celdas de RAM (<1K).} + TCPURamCellPtr = ^TCPURamCell; + TCPURamCell = object + private + Fvalue : byte; //value of the memory + function Getvalue: byte; + procedure Setvalue(AValue: byte); + public + addr : word; //dirección física de memoria, en donde está la celda. + name : string; //Name of the register (or variable) + used : boolean; //Indicates if have been written + shared : boolean; //Used to share this register + 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 AvailGPR: boolean; + 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} + public //Information of position in source code. Used for debug + rowSrc : word; //Row number + colSrc : word; //Column number + idFile : SmallInt; //Index to a file. No load the name to save space. + {Estos campos de cadena ocupan bastante espacio, aún cuado están en NULL. Si se + quisiera optimizar el uso de RAM, se podría pensar en codificar, varios campos en + una sola cadena.} + topLabel : string; //Label on the top of the cell. + topComment : string; //Comment on the top of the cell. + sideComment: string; //Right comment to code + end; + + TCPURam = array of TCPURamCell; + TCPURamPtr = ^TCPURam; + TCPURutExplorRAM = procedure(offs, bnk: byte; regPtr: TCPURamCellPtr) of object; + +type + + { TCPUCore } + {Abcestor of all 8 bits PIC cores} + TCPUCore = class + public //Limits + {This variables are set just one time. So they work as constant.} + CPUMAXRAM : word; //Max virtual RAM used by the CPU + public //General fields + Model : string; //modelo de PIC + frequen : integer; //frecuencia del reloj + MaxFreq : integer; //máxima frecuencia del reloj + //Propiedades que definen la arquitectura del CPU. + MsjError: string; + public //Execution control + 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 + minUsed : word; //Dirección menor de la ROM usada + maxUsed : word; //Dirección mayor de la ROM usdas + hexLines : TStringList; //Uusado para crear archivo *.hex + public //Memories + ram : TCPURam; //memoria RAM + iRam : integer; //puntero a la memoria RAM, para escribir cuando se ensambla o compila código. + function DisassemblerAt(addr: word; out nBytesProc: byte; useVarName: boolean + ): string; virtual; abstract; //Desensambla la instrucción actual + public //RAM memory functions + procedure ClearMemRAM; + procedure DisableAllRAM; + procedure SetStatRAM(i1, i2: word; status0: TCPUCellState); + function SetStatRAMCom(strDef: string): boolean; + function MapRAMtoPIN(strDef: string): boolean; + function HaveConsecRAM(const i, n: word; maxRam: word): boolean; //Indica si hay "n" bytes libres + procedure UseConsecRAM(const i, n: word); //Ocupa "n" bytes en la posición "i" + procedure SetSharedUnused; + procedure SetSharedUsed; + public //ram memory functions + function UsedMemRAM: word; //devuelve el total de memoria ram usada + public //Pins fields + Npins : byte; //Number of pins + pines : array[1..PIC_MAX_PINES] of TCPUPin; + procedure ResetPins; + procedure SetPin(pNumber: integer; pLabel: string; pType: TCPUPinType); + function SetPinName(strDef: string): boolean; + public //RAM name managment + function NameRAM(const addr: word): string; + procedure SetNameRAM(const addr: word; const nam: string); //Fija nombre a una celda de RAM + procedure AddNameRAM(const addr: word; const nam: string); //Agrega nombre a una celda de RAM + public //Execution control + procedure AddBreakpoint(aPC: word); + procedure ToggleBreakpoint(aPC: word); + procedure Exec(aPC: word); virtual; abstract; //Ejecuta la instrucción en la dirección indicada. + procedure Exec; virtual; abstract; //Ejecuta instrucción actual + procedure ExecTo(endAdd: word); virtual; abstract; //Ejecuta hasta cierta dirección + 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 Reset; virtual; abstract; + 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 + procedure addPosInformation(rowSrc, colSrc: word; idFile: byte); + public //Initialization + constructor Create; virtual; + destructor Destroy; override; + end; + +implementation + +{ TCPURamCell } +function TCPURamCell.Getvalue: byte; +begin + Result := Fvalue; +end; +procedure TCPURamCell.Setvalue(AValue: byte); +begin + Fvalue := AValue; +end; +function TCPURamCell.AvailGPR: boolean; +{Indica si el registro es una dirección disponible en la memoria RAM.} +begin + Result := (state = cs_impleGPR); +end; + +{ TCPUPin } +function TCPUPin.GetLabel: string; +{Devuelve una etiqueta para el pin} +begin + case typ of + pptUnused: Result := 'NC'; + else + Result := nam; + end; +end; +{ TCPUCore } +//RAM memory functions +procedure TCPUCore.ClearMemRAM; +{Limpia el contenido de la memoria} +var + i: Integer; +begin + for i:=0 to high(ram) do begin + ram[i].dvalue := $00; + ram[i].used := false; + 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 + end; +end; +procedure TCPUCore.DisableAllRAM; +{Inicia el estado de toda la memoria RAM física definida em el Modelo. +Solo debería usarse, para cuando se va a definir el hardware del dispositivo.} +var + i: word; +begin + for i:=0 to high(ram) do begin + ram[i].addr := i; + ram[i].state := cs_unimplem; + end; + //Inicia estado de pines + for i:=1 to high(pines) do begin + pines[i].typ := pptUnused; + end; +end; +procedure TCPUCore.SetStatRAM(i1, i2: word; status0: TCPUCellState); +{Inicia el campo State, de la memoria. Permite definir el estado real de la memoria RAM. +} +var + i: Integer; +begin + for i:=i1 to i2 do begin //verifica 1 a 1, por seguridad + if i>CPUMAXRAM-1 then continue; //protection + ram[i].state := status0; + 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: +, , ... +Cada comando, tiene el formato: +-: +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. +} +var + coms: TStringList; + add1, add2: longint; + state: TCPUCellState; + staMem, com, str: String; +begin + Result := true; + coms:= TStringList.Create; + try + coms.Delimiter := ','; + coms.DelimitedText := strDef; + 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.'; + exit(false); + end; + if com[4] <> '-' then begin + MsjError := 'Memory definition syntax error: Expected "-".'; + 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; + 'NIM': state := cs_unimplem; + else + MsjError := 'Memory definition syntax error: Expected SFR or GPR'; + exit(false); + end; + //Ya se tienen los parámetros, para definir la memoria + SetStatRAM(add1, add2, state); + end; + finally + coms.Destroy; + end; +end; +function TCPUCore.MapRAMtoPIN(strDef: string): boolean; +{Mapea puertos de memoria RAM a pines físicos del dispositivo. Útil para la simulación +La cadena de definición, tiene el formato: +:, , ... +Cada comando, tiene el formato: +:- +Un ejemplo de cadena de definición, es: + '005:0-17,1-18,2-1,3-2,4-3' +Si hay error, devuelve FALSE, y el mensaje de error en MsjError. +} +var + coms: TStringList; + add1, pin, bit: longint; + com, str, ramName: String; + pSep: SizeInt; +begin + Result := true; + //Obtiene dirección + if length(strDef) < 4 then begin + MsjError := 'Syntax error'; + exit(false); + end; + if strDef[4] <> ':' then begin + MsjError := 'Expected "<3-digits address>"'; + exit(false); + end; + if not TryStrToInt('$'+copy(strDef,1,3), add1) then begin + MsjError := 'Address format error.'; + exit(false); + end; + delete(strDef, 1, 4); //quita la dirección + //Obtiene lista de asociaciones + coms:= TStringList.Create; + try + coms.Delimiter := ','; + coms.DelimitedText := strDef; + for str in coms do begin + com := UpCase(trim(str)); //asociación + if com='' then continue; + pSep := pos('-',com); //Posición de separador + if pSep = 0 then begin + MsjError := 'Expected "-".'; + exit(false); + end; + //Debe tener el formato pedido +// debugln(com); + if not TryStrToInt(copy(com,1,pSep-1), bit) then begin + MsjError := 'Error in bit number.'; + exit(false); + end; + if not TryStrToInt(copy(com,pSep+1,length(com)), pin) then begin + MsjError := 'Error in pin number.'; + exit(false); + end; + if (pin<0) or (pin>PIC_MAX_PINES) then begin + MsjError := 'Pin number out of range.'; + exit(false); + end; + if pin>Npins then begin + MsjError := 'Pin number out of range, for this device.'; + exit(false); + end; + //Ya se tiene el BIT y el PIN. Configura datos del PIN + pines[pin].add := add1; + pines[pin].bit := bit; + pines[pin].typ := pptPort; + ramName := ram[add1].name; + if ramName='' then ramName := 'PORT'; + pines[pin].nam := ramName + '.' + IntToStr(bit); //Nombre por defecto + end; + finally + coms.Destroy; + end; +end; +procedure TCPUCore.ResetPins; +{Reset the pins of the device.} +var + i: byte; +begin + for i:=1 to Npins do begin + pines[i].nam := ' '; + pines[i].typ := pptUnused; + end; +end; +procedure TCPUCore.SetPin(pNumber: integer; pLabel: string; pType: TCPUPinType); +begin + if pNumber>PIC_MAX_PINES then exit; + pines[pNumber].nam := pLabel; + pines[pNumber].typ := pType; +end; +function TCPUCore.SetPinName(strDef: string): boolean; +{Define the name for a specified Pin of the microcontroller, using a string. +"strDef" have the format: +: +On error this function return FALSE, and the error menssage in MsjError. +} +var + com, pinName: String; + pNumber: integer; + pcol: SizeInt; +begin + com := UpCase(trim(strDef)); + if com='' then exit; + pcol := Pos(':', strDef); + if pcol=0 then begin + MsjError := 'SetPinName: Expected ":".'; + exit(false); + end; + //"com" must have the correct format + if not TryStrToInt( copy(com, 1, pcol-1) , pNumber) then begin + MsjError := 'SetPinName: Wrong Pin Number.'; + exit(false); + end; + pinName :=copy(com, pcol+1, 32); //limited to 32 + SetPin(pNumber, pinName, pptControl); +end; +function TCPUCore.HaveConsecRAM(const i, n: word; maxRam: word): boolean; +{Indica si hay "n" bytes consecutivos libres en la posicióm "i", en RAM. +La búsqueda se hace solo hasta la posición "maxRam"} +var + c: Integer; + j: word; +begin + Result := false; + c := 0; + j := i; + while (j<=maxRam) and (c cs_impleGPR) or (ram[j].used) then exit; + inc(c); //verifica siguiente + inc(j); + end; + if j>maxRam then exit; //no hay más espacio + //Si llega aquí es porque estaban libres los bloques + Result := true; +end; +procedure TCPUCore.UseConsecRAM(const i, n: word); +{Marca "n" bytes como usados en la posición de memoria "i", en la RAM. + Debe haberse verificado previamente que los parámetros son válidos, porque aquí no + se hará ninguna verificación.} +var j: word; +begin + for j:=i to i+n-1 do begin + ram[j].used := true; //todos los bits + end; +end; +procedure TCPUCore.SetSharedUnused; +{Marca las posiciones que estén en "shared", como no usadas, para que se puedan +usar nuevamente.} +var + i: Integer; +begin + for i:=0 to high(ram) do begin + if (ram[i].state = cs_impleGPR) and (ram[i].shared) then begin + ram[i].used := false; //pone en cero + end; + end; +end; +procedure TCPUCore.SetSharedUsed; +{Marca las posiciones que estén en "shared", como usadas, para que no se puedan +usar nuevamente.} +var + i: Integer; +begin + for i:=0 to high(ram) do begin + if (ram[i].state = cs_impleGPR) and (ram[i].shared) then begin + ram[i].used := true; //pone en uno + end; + end; +end; +function TCPUCore.UsedMemRAM: word; +var + i: Integer; +begin + Result := 0; + for i:=$0000 to CPUMAXRAM-1 do begin + if ram[i].used then inc(Result); + end; +end; +//RAM name managment +function TCPUCore.NameRAM(const addr: word): string; +{Devuelve el nombre de una celda de la memoria RAM.} +begin + Result := ram[addr].name; +end; +procedure TCPUCore.SetNameRAM(const addr: word; const nam: string + ); +{Escribe en el campo "name" de la RAM en la psoición indicada} +begin + ram[addr].name:=nam; +end; +procedure TCPUCore.AddNameRAM(const addr: word; const nam: string); +{Escribe en el campo "name" de la RAM en la psoición indicada. Si ya existía un nombre, +lo argega después de una coma.} +begin + if ram[addr].name = '' then begin + ram[addr].name:=nam; + end else begin + ram[addr].name+=','+nam; + end; +end; +//Execution control +procedure TCPUCore.AddBreakpoint(aPC: word); +//Agrega un punto de interrupción +begin + if aPC>=CPUMAXRAM then exit; + ram[aPC].breakPnt := true; +end; +procedure TCPUCore.ToggleBreakpoint(aPC: word); +//COnmuta el estado del Punto de Interrupción, en la posición indicada +begin + if aPC>=CPUMAXRAM then exit; + ram[aPC].breakPnt := not ram[aPC].breakPnt; +end; +procedure TCPUCore.addTopLabel(lbl: string); +begin + ram[iRam].topLabel := lbl; +end; +procedure TCPUCore.addTopComm(comm: string; replace: boolean); +{Agrega un comentario de línea al código en la posición de memoria actual} +begin + if replace then begin + ram[iRam].topComment := comm; + end else begin + ram[iRam].topComment := ram[iRam].topComment + comm; + end; +end; +procedure TCPUCore.addSideComm(comm: string; before: boolean); +{Agrega un comentario para que apareza al lado de la instrucción. + "before" = TRUE -> Se debe llamar después de codificar la instrucción + "before" = FALSE -> Se debe llamar antes de codificar la instrucción + } +begin + if before then begin + if iRam= 0 then exit; + ram[iRam-1].sideComment+=comm; //se agrega al que pudiera haber + end else begin + if iRam= 0 then exit; + ram[iRam].sideComment+=comm; //se agrega al que pudiera haber + end; +end; +procedure TCPUCore.addPosInformation(rowSrc, colSrc: word; idFile: byte); +{Agrega information de la posición en el codigo fuente, a la posición actual de la +memoria RAM.} +begin + ram[iRam].rowSrc := rowSrc; + ram[iRam].colSrc := colSrc; + ram[iRam].idFile := idFile; +end; +//Initialization +constructor TCPUCore.Create; +begin + hexLines := TStringList.Create; + frequen := 4000000; //4MHz +end; +destructor TCPUCore.Destroy; +begin + hexLines.Destroy; + inherited Destroy; +end; + +initialization +end. +//659 diff --git a/Cambios.txt b/Cambios.txt index 07d4044..3f7c6e2 100644 --- a/Cambios.txt +++ b/Cambios.txt @@ -1,5 +1,10 @@ +0.1 +=== +Se eliminan algunos campos no usados, porque esta librera se ha creado a partir de la librera +PicUtils que contiene ms detalle en cuanto al hardware. +Se corrige errores en el ejemplo de ensamblador. + 0.0 === - Primera versin compilable de la librera. An queda pendiente la implementacin de la ejecucin de las instrucciones, y revisar todo la librera para quitar elementos no usados ya que esta librara se ha creado a partir de la librera PicUtils. diff --git a/MiniAssembler/project1.exe.hex b/MiniAssembler/project1.exe.hex new file mode 100644 index 0000000..269f46c --- /dev/null +++ b/MiniAssembler/project1.exe.hex @@ -0,0 +1,4 @@ +poke 0,165 +poke 1,0 +poke 2,133 +poke 3,0 diff --git a/MiniAssembler/project1.lpi b/MiniAssembler/project1.lpi new file mode 100644 index 0000000..a32364f --- /dev/null +++ b/MiniAssembler/project1.lpi @@ -0,0 +1,80 @@ + + + + + + + + + + <ResourceType Value="res"/> + <UseXPManifest Value="True"/> + <Icon Value="0"/> + </General> + <i18n> + <EnableI18N LFM="False"/> + </i18n> + <BuildModes Count="1"> + <Item1 Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <local> + <FormatVersion Value="1"/> + </local> + </RunParams> + <RequiredPackages Count="1"> + <Item1> + <PackageName Value="LCL"/> + </Item1> + </RequiredPackages> + <Units Count="2"> + <Unit0> + <Filename Value="project1.lpr"/> + <IsPartOfProject Value="True"/> + </Unit0> + <Unit1> + <Filename Value="unit1.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="Form1"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="Unit1"/> + </Unit1> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="project1"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value=".."/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/MiniAssembler/project1.lpr b/MiniAssembler/project1.lpr new file mode 100644 index 0000000..2500258 --- /dev/null +++ b/MiniAssembler/project1.lpr @@ -0,0 +1,21 @@ +program project1; + +{$mode objfpc}{$H+} + +uses + {$IFDEF UNIX}{$IFDEF UseCThreads} + cthreads, + {$ENDIF}{$ENDIF} + Interfaces, // this includes the LCL widgetset + Forms, Unit1 + { you can add units after this }; + +{$R *.res} + +begin + RequireDerivedFormResource := True; + Application.Initialize; + Application.CreateForm(TForm1, Form1); + Application.Run; +end. + diff --git a/MiniAssembler/project1.lps b/MiniAssembler/project1.lps new file mode 100644 index 0000000..46cf53e --- /dev/null +++ b/MiniAssembler/project1.lps @@ -0,0 +1,148 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectSession> + <PathDelim Value="\"/> + <Version Value="10"/> + <BuildModes Active="Default"/> + <Units Count="5"> + <Unit0> + <Filename Value="project1.lpr"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="-1"/> + <WindowIndex Value="-1"/> + <TopLine Value="-1"/> + <CursorPos X="-1" Y="-1"/> + <UsageCount Value="60"/> + </Unit0> + <Unit1> + <Filename Value="unit1.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="Form1"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="Unit1"/> + <TopLine Value="152"/> + <CursorPos Y="171"/> + <UsageCount Value="60"/> + <Loaded Value="True"/> + <LoadedDesigner Value="True"/> + </Unit1> + <Unit2> + <Filename Value="..\p6502utils.pas"/> + <UnitName Value="P6502utils"/> + <IsVisibleTab Value="True"/> + <EditorIndex Value="1"/> + <FoldState Value=" TL00C1414113 T4H01 T5J0{W11]ACjEK5 T7jPJC T8jQ26132 T3m8051]ZD2]E0nFD7I2K T6n601D THnEF%2?"/> + <UsageCount Value="32"/> + <Bookmarks Count="1"> + <Item0 Y="1211" ID="1"/> + </Bookmarks> + <Loaded Value="True"/> + </Unit2> + <Unit3> + <Filename Value="..\CPUCore.pas"/> + <EditorIndex Value="2"/> + <TopLine Value="472"/> + <CursorPos X="6" Y="486"/> + <FoldState Value=" TL0040211193 T4801 T5A[64CED8 T7dC6 T8iE230122145 T3kX0331]mHl8B4]i6lI01A T0leR3C pjAjYN3857 TDmZ2e]ZEnU]+'"/> + <UsageCount Value="25"/> + <Bookmarks Count="1"> + <Item0 Y="117" ID="3"/> + </Bookmarks> + <Loaded Value="True"/> + </Unit3> + <Unit4> + <Filename Value="C:\lazarus\lcl\include\control.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="2838"/> + <CursorPos Y="2861"/> + <UsageCount Value="10"/> + </Unit4> + </Units> + <JumpHistory Count="22" HistoryIndex="21"> + <Position1> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="1223" Column="3" TopLine="1169"/> + </Position1> + <Position2> + <Filename Value="..\p6502utils.pas"/> + </Position2> + <Position3> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="208" Column="30" TopLine="167"/> + </Position3> + <Position4> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="363" Column="17" TopLine="254"/> + </Position4> + <Position5> + <Filename Value="..\p6502utils.pas"/> + </Position5> + <Position6> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="226" TopLine="211"/> + </Position6> + <Position7> + <Filename Value="..\p6502utils.pas"/> + </Position7> + <Position8> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="259" Column="21" TopLine="218"/> + </Position8> + <Position9> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="355" Column="65" TopLine="252"/> + </Position9> + <Position10> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="368" Column="5" TopLine="265"/> + </Position10> + <Position11> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="373" Column="32" TopLine="265"/> + </Position11> + <Position12> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="1060" Column="49" TopLine="963"/> + </Position12> + <Position13> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="1085" Column="49" TopLine="1064"/> + </Position13> + <Position14> + <Filename Value="..\p6502utils.pas"/> + </Position14> + <Position15> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="370" Column="8" TopLine="354"/> + </Position15> + <Position16> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="369" Column="28" TopLine="354"/> + </Position16> + <Position17> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="1148" TopLine="1141"/> + </Position17> + <Position18> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="207" Column="33" TopLine="180"/> + </Position18> + <Position19> + <Filename Value="..\p6502utils.pas"/> + </Position19> + <Position20> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="1077" Column="62" TopLine="957"/> + </Position20> + <Position21> + <Filename Value="..\p6502utils.pas"/> + <Caret Line="1446" Column="12" TopLine="1155"/> + </Position21> + <Position22> + <Filename Value="..\CPUCore.pas"/> + <Caret Line="155" Column="6" TopLine="121"/> + </Position22> + </JumpHistory> + </ProjectSession> +</CONFIG> diff --git a/MiniAssembler/project1.res b/MiniAssembler/project1.res new file mode 100644 index 0000000000000000000000000000000000000000..877868cb4251927ab961b2295948c0d753ecb7cd GIT binary patch literal 138932 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%0Dyf&^Ri6{F0PF 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�naFVJ}8`g;O3<vub`1MHe&zT1Sh zM%zGdk<Tvhri;t{&=#~Qr7iI1_66k9CLBwME<sl1%gX$#urH`{td}}XYf|bI$8Wb8 zvbhPF+}IF6*VnhDoHcFe{4!rUHrJE(j(4KeLDm>EH$cBoRmcVWwH4pmT3K>FxEuJd z0S$#;c7PAyb!271LrLZV!WbX>7t~>fy87E%ny>NKR(QjHpLtpmZb+$vMYL~{D;=Nb zP3IF^)0H)C>DszL;Gahug3!K_rBIiq|61$|>H&YQU$X*D=wbYA89-LoLD!N4=<=#I zbT+|{vS)eHuCY$YsVr%_zczJ1oMoTuqu2N`u;4hb9mH#hx`1>!H-`@Jnt_t~<F$Jg zQ8usD4Ft_-rPt(EpjHFST`37XZR}?y@OX5NH=SMDnl7yhpsUGf$NC`Xa~`GOSi)4P zeDV5u5YR8zpGNYsbTk1u|Ch4Jlhd`7VAxF%<v@NHSG1+mi~Z>EbWh3{?m+8$n$vK% zmO>l|(3B%rW9`epgXfGl0v|jtA^2wHyj-v(e1I^w1N`eC=A#PhC?`|>9RV5*gnsEz zm*yC^v;c38bZEL4onGQk7gq+r_Je?bFkM~8ZTUI0C`$Cpu`4Nkk&%|7QJoCGDx0h8 zbLEzk97LDb1k#1&0d#VqA7#aPP<oUd);^n1FO09S@AcPG_zQ91FmT~{qGdSt0U3gL zO?gT90KxW=U#P+Nhu~rQxvjO8Ua<e^YOYF&?Tsld(jL5d(uoDF>3mWEY(E(IhtQSe z5a@8|Pos{WE&o{j^Yy4#Ypp`%!}7bbCK&PzqI1gv=;&Nu+CAQlHVv?$S#5REA5fw| zEjjYiZ*~{h^VlFihZqYxZH1#U@<8qn7RLt&ai47;<zX7aI?COk#fbn7Im}NeQJjw! zZRm$Nta0v?J=c%UEXDg%SAyTwq0rk9y1W+0pGZEUMt?m1l9Cd%Y=mRsa)KN$tq!3J zD}w3NlD2esh7bDIE|lEEk|Ld&BNxOxkw$}$4(7%ufe)Tf7JLBjRbWs8d4Lphz6vOd zpKA}cvoJ|$qbc{EZNHzWDc0+m)3#yGbO=11S{z8{l7i{ts!##{ORK|h{JGS@<IlH$ z_5)>0%TV?b_|3xP1({x08A|68gXzS=Hk38lo3;$Lr-X20jJc?wKPX3j+A1%AQ@#(F zgwMQgObNF8!+imcAH1dm{=^*R4e`=#e7UV=1Htwe1R2og2z%N)$%~FHXiI071=INz z%x4%VoGz^T`E)8Nl%%EqUH$%izh2a%3vet{W-QMYVX&`II-L+q*|Ys==NNZd-&;iE zJvAvrNALmUY@&MsK7jLp1RVMKSzTbrdr|zz95Ijgl!e`^pd4R&OVb7LGauOYqa4&Q zCS^q#Bi-omOn>;L5IUO({+5S92f}|TwYL3p`hVZji7FM#d|Pgi?YX2d*jXr@h!3Lu zQ++8t+L@MjG^4Jjs)7&j)mCO7z<q%YAl~=J3Ha3q{=9CqNPny|xS#jl&_NkJz4V%% zVcQSYSE2<$+}C%ceQ_9{SP(>~mxj^Vq;T-}d#E*H5gPZ$(>7rGEg7<m&%n-3C4^A+ zoB-N2&Wlp|+6q2^`vR~}Lf`BxaN}o=c`u_d&f7VLLq0{y19?3ku&)Q~9c;`^<NP%m zyyskVkZm)pUB%k9(Vld8R$Dr;2tH{k_*(XRsWbfGpRNP#UDdxY$HaDs0bz7}VF(?V z=1=J{u9Vc?lsXx!5ZkAZw#qZ$&d(9>+|XcPZw5ckd)O7FFDS`ly|}jt$_nz-Yj%Wn zD;T-voVEtEDS~akH65K7OedFw(<$J8dMWt&%{02B1xfwO<^hVLlcCP)-<9Dh$oN!3 zIP5Nrj?4+9o#R{4x<0lv+FhLj5u4kn*C$6a!&AV23$TmB(Tn#}DaslV_Wiu35BC~~ ztSlq^HRRr~ZuPTjOsl$D()JM^bZ}-M9g7d66N}qH2mU=YZ=e&w(fyIWptFaTc(R1d zPb?0nqYFYQYib)xi*li*;U;+2SV@Qh-nxw+0(;H_7vtC&#Cs4`gf5CTH_UU0=sVVB z-|uRqxrTL$eg9-{JoDb)fp$-7O-JU2(6L3#$G?x<O#jSrfj)lvV$1XRqV{xbVK^O{ z9gJAqiq`hDp(uMb;;|XT>JJzb<n@Bdz&?s&0FL602TJnTF=Bs1+|$NKTlI2Vjr!Cc zd0%3<8R8A*B&P*Z_PlV^-wr;Ycr>%G18Fs?i@A|X#5r)8Qqlq`)|Dl9)5gTV|41FB zQBF~O@4w;NDLrkA)>g>>$lNg68{3994RWEGt@S>|0N5?h3v2=LSb!V+e*-a}9g^ZT zy|_oy*1~jP8}$Ys*!M@-;rYxSHnd}`AAEl(@NY-i3);g6{TK~wV+_2@iiHu6m4`ZN z6sa!l#&yLi``>^&^T2CUiz>_P1;8J6xPN*OZ5!^5zMutlHbNeVT#fTUV94u3=E08# zqaV<i*XyFLZ}tN?Ph?-gV?G}GYAJ&6$N17LKRwzQ;X-@j0^oCyd(3T*y1D+M(SbQ( zq}R0m4`EZed>L9l+E=VPeXZ1fsE*&I4|26Ci`A|#<$W0PKR7cCd7wWf_p+zqPA!Cf z0ON)+8|*V7>|5H4`|-R+@H=b8g}FZHOMP7L>Z_%6gUjiJd4{BR=9E6n8~H{s9h}{c z4$mn%?VAxo)hm}P7A|ElR=R$q?|19>GW)Z}1Y$z)EZh&s^bqbjI4hj?Ob$d0aHIMD z2E_BijGMb*%WJS@-g|5)$Wn}c;HTJcV`(0WGCpwZk4B$=b$2_;7~@Y_)5GY%taiBs zJvdMVQm7+aEbQ}bvqIU@lr{6)b-NiiE|I$O>-?F=#&Xq*B*)KW&REP0r+rgHY3s07 zuu}`_Vx%nKkKFAka8H9hV?R9`-fyY?cX9w>t`|O|g`1Ja6xJb*C6hh1C}n^P?VK2h z+%Jsw&uCX<GHxzkqIh_jHTxzHP6mHQAAtRS>bQV!w&i>B&YBMVflJ1iHh7NEjv_@( zfLnc`AAtFKeuj7!F!cxiD)0e?&IfU9;244Hb<v01&iDtR-?uo>h*BfHXxF4*+B=o& zDjH4g=2)WGvn@&^U)mKHS|~5}da5N}XG!@0=Dl{+iqy;7piuscD&xIV!f3~YKw96= zm15mA1-oVZ98L9)0?$RjzkPwR;IEDY<d6H{dQ(45#p`^3H~5moc9w|!ezYq#gm%Y; zA=VU)s#h-mQ?M8vCMuK{2i<=U{@i|@M)fGnL5mjkcQ2IZqRRE}>q7-xc1{SUO+&nB zVOt{#z}h^<&%>a_HDHhZ(M7$0zc#NAE-VM++~3H^s21k=U2*RRzCQ}SWK~yN+BUKc z{C^1ToD>Q_AU^f*F!(9hvn{$BHZGKx$(<d3TD{`<0Um?YZ_<F4MX=u#UtT|Y?aoOd zu>WA%65~h9!px})#sV2X^aGy)`?a9K@c%}@Shf)Sg|$A&6Y6;wsSo0NIfhJfQK#hI zF0^fQ0A-F30b#tU2vo0nrJsg_NK^Tnyl|c<4pt?74X@{j?P&i^-ijhav9BE$Lg~Z( zX+<X+8jP`e#*oJXfj#d@J_3H7_nWQGejaW9@-P3{9tAJmCUbJ}Z$Ptsb&>md!2Sbi z`<S32QR;{QJeTqF#^S^6wZ6%Zowmv^$Dik)mJaaxCSOIBV^OY8AKn&yHAfm{-(0|- zal|+PuL~Ow?Cn9d+0TCoKF)>p9=J}~M@MxN-xrMBFTSlIZ5-rH>A-R;bYSZ!@u{Pe z&QFs+%XvvZ&u{XxA;zC7mHV|mAk0?tn>-aoenq|(_@n{<<UVc`=cfJ%e`ixYeoln< znRQ|RUdS_IpZflOT8hUQ|IT=hdr6QfZ5-@FX~WtUnN;dl{b~3IS*eS~&ywCAR0`wA z(C?p4s`aXg#nX?-QrvsC3~fv6`g_t`AKg!V0Cz+6bHINJ@b`f2H-P{D+CFl^oIieV zg8ANijDKGfRazQqA>f}H?N3D|9=9)Px%2Z>9tKT{#LJ{m8}t`To|l4cD=i~UYa)D# z#8*+}DbDqqqx@<80B>5@+JHi}vF9*w#M-SJ@cYw2yhn>dA!`97d7Y50g_%0;`N;Q0 zS~kL-l_J_O$d@(_X<Z~56JTB9*jKMqj%IdnED|62e6Q@^iZqq$lsHeU1Dxwe`k4I? zU-|r%<dN}T6kv=#fTDmu`T&n$|1*KVFEB1_O|Y=m+sR1VoUvybj&a}Ro$M)PppT#f z8wUH5xMb2)uEb=`Ht(j_NbI`5#p9$98>){!NlC2}DqBj1Mh94m#amBjJyMgaK}{M| zr)CXm;B!rCAzzc)+u}KjBFOfe*ADWd_0aVtL1xq&&j~V)ep*V;f&DDlKJOo=3?Kis zF+c%-SA&+0`S_1U4!NR>1N?~(r9}7@iDWB?H@92RhkosI^-ASwMtjF1)h#ZsQLtIl zrt-vog>~#}^?&O-)jCyaRX^`<^0uIht565Whi{d|zniNmP(ly)Z<Z%c+t&4KMG1)8 z{mmN+__x+ncqIn@g8#>yZ!5;1$Nk4UwxE?=ooU?wUqJ_055%EWeZ0Tf)^Eun|2M(r zbsLFQpEx{y@0w(^t-qTg={KxTvgOMbx`vF$6bu_Rps{VOzssA8cEcjefn$k|a^3Hi z{jK&S_w}ZwVb&C3nLh>~_ZRGbM!x?qEdKMFPfwl3f%*7Pa%o8`ySvi5em>9vKe4HU zt#*;yosT;oYs*%oS?!&~uCFM(iF@s8w0TTh5shqZMZ^6pDaOZwW_Ms)5Kj(X2F06y zR<2!@){0rzmprZQ+lrR8v!O_<rg?pU1|NX^G|)HmKVJ9cqtmcsKK_&4G-zcvS6bT# z>&yE2icQTB*9zh(?q`n4e#XtkuBRwG{mN?t&DDRX{a?ySwNAAklLh=Q;~yhx_NfnO zV{OIxzx%iPf1DTiYOC}T@W&d086KJf{%ZvMeZY%&R0aOCU|YoL2g+5iO!GRqh+T)c zy!?*qDwHX?F{eH*hDDP}Umsf2+Y8TS+tF~l=AZDlvovS_@679Z3mgC8xB&dS<l{fx zU5l1?b)hxAylE}U6_?6k{JS9jWBjej+o0K3$AWpiXQ-uy*ky~$!|%FoX?M@h+Fno& zKk~VJnNmfP4cqGKUY@Xj;BWgk{#eg5899I*`hT@x=U*NFWxW9YZS(P;;;v0eon2^k zPj6b?8|8{g1?{~i=05Z9n-%Uv;Z~YtsisJx7D_ZRz~<9$`PcmE$K^e}N)&(AneoU& z#Fh(ebyW{f<bSplW25%T{;jPnM*x2d_<+LZe<WBhT4^ae=i?vi3j8}dp*-N<i}Cjn ziwgFox;yBLb&t4Z{|VQX)YwA4zp&R(6<>zHX=Qg0JP%@vxqIM`IL^=R0e61apdm0W zZ2nh*=LNmBR7~^npWupjpmuPemCz>vf7Sspi1DvqtrCS;Xoz*aIA#7x*KppJk6lR| z6>3xwTaK&XtCx3mr-Tp@4Yo%92mD)W$iD{mJuv>G#cTV)(^uF3@VWr(Db*q$|FO;* zc;})$t?1@KT<)r#t;C{bUA@G*PTcaoc3o0;FB;`*MWN8KzD|bpE9(3jA7A@!sJBIl z;$N$B1@YwxU%jH6J1q&erh!&@_-iUW1@__4fo9yt2mXaU10dzC-%Kta|5146VrjS? z^vQ!(GWNZEe=Ch{Eh4t9!sc>#ELOgTEDdxs{jGemoGO<qQ(`($17o1#%6=vAUyht@ zagZhTF>5T?Kjw4q0ee5h|H8(8p%TKMq_vqzIpF`A{YIp13ydS$0Dm{&5Bu-s^IK?6 zI~S@|r9zS9S+{B>8sl&CTli%;wbE}^Bz__NLa(n{p`6(5VEj2}UlfRS;KmJw{15X# z7lFU?H|GBH;Fpl#_2GEt>onuv*P<yc4z@yhZty>x`}zHHiVJd}?~R>*OLqRoEq*!A zET@%_7q9dE7H{JIrc|q{SZ!F<3-$JBMTs3<D87vuh3e)$4~%_#b_09fr~kXpfN~Cq z`Tu0bzl%{rto^oxKXFC=fpLXCt$!)a40j=!V$R!hE;^>Q?Jwm!UrxFzKlYs4mwI8> zQdMmJ*-jHXIMHlBBRmV5yDt#tbe3`M$M1_l*<a25@O}QD6!0I*^FJZbpZEYX*gx<G z_G|mM{iP&_ycbLrn>a664x9Yd{Lky`S?D}cQQ8&ZVJ;T$Yx=bj;>0qnk%;xev%p$- zcL?V4+>Et`!S)-8xhJS3@DE}9S$}5x8VmTZ>5JzJ2L@4c#IK<q&Zfo2y`YQ(EVK&c z-QQG`nl`9K^{Q2-${4%mF*lxrQj@PuHX4m+T##d-_kK?vDs`$CyB(_r1c+7t+5v&I zs<$utYz{QaNej;b=C1#-H#g#EfAXLG%D3}EkACWM`m8ssKNH<`5l@^1|FaJGuNxHd zOQ>AwQpJ{ALHrxmt?>`OLq&SR-g^bFE9|qGnli2ZfwqqcbShRmWRd%cEA!-mz#nls z0b_rIZJG=C!<Jtn?>FJSAPZUd{SQ6xGuJ5t{GYS_MB1s-(suR&{_6*YQc7g_Pp1Vv z{E8*BuVL7zUd_+=?&4%z<T@&1?tg5M^JnFVBaa&BzkiJ<alY&CX(e`j>mq`Mae^fw z*4PiKk<j<UGu(L3ylr!g`-#2(3;2=*{;8Y;b~VBKnb8O2oHk`h7;T8|KpTHD1zGF; zu)GSBsfS_9Pkhhn;`_tvzj*9nW@n#IWr-t;KJJ!3)SlY1mBg-xabZ8P660d?koyPc z<^Fh%b1v*(zK}H^5ZBlL{M8!_;2eO<ncvo2&@0yUjYB)prlFmGDz#K9nY<Y-6Xee0 z@yq&$eB#-%W$~U3=Ge3%BK%W%;>e@y55%+4!Px6rOj&P?=_ug8yo)=H_t5{8`@0&d zw=IhA&({XOmi2V<bHIsS2ErIH+yACvT_|-#x1UNis#N?Td&$T9%Oln_e#UPt*wvTU z6!pAjl}eC>_;O$#ic&{yj9-Z>=gq^r3VOo%8Ru$)5VJXUW8UW}{C<<~jQN7CfBu;& zRFg&wc*NxlMtO-HvGxi6h3ncfs^?Fodeuv2p9r*yDq<Y=OMVL*Kj!O;Laoen{!#Xq zbrn3XTTT4_>_A@!vCB>!)kDCa`?ow^-!U)tW88NKzoRj4&xe14{GD%r{|e3l+8Z`R z4q%5qXn=r!+UVYtHnz`CBh~t~i-g0sFdG`={trG2&QE{q-tYaUSiAZ^%KnyIRz-Kl z-e#Y#jrm#~th3)L=gZ%=jP51G<<*#XnC@r#DfVM6Uo_TqR6!kId)^aYfBVm0y}ldA zfFK=3ifd&g^ex!`r;qJRTgUgKtrPnH6w*{xC=vXP)KtI9UrFIFBQ5>a^1mmS$N*Q; zYobh*(YFHv{~#|jUGd8W4ryb0(}t+_#Ib*fy=MNn&s#kA$M1#w;djHr{!4-Ga|{?D zQpY&3n~?vfkL^d>CJv-+lOlc!IqDaG{iJNg3Y0$K>-?1z{*2wmF_1+u<WQmP=ktWj z+r}|{#4i&#q>bq%#O4I}{`N+>{XVSuPvf;7;`aFq^91k#Q#l5N8mQuZzP7}DO!hz9 zV+T>j<RL$W77y<951aU!ofP&R%aF?`jK7jvpTqSOR)@IXm-^zlkVbNKi&Q4-9>;&4 zbBJwa{K@yX(pC)y{$G2}r!c6$`n`Y4`nvfsV62CMFb=@=ZI2sFnNy>G8WrXn3&XtN z_lk9Dev>cu+Xb)x(a+qcE3OQ_+#g|VCx7wFoDwDY3GO5EnxB56mU+Iv!9!PDtD42N zeaJ=lLku{<F`z5<)Jwz~Z65Pr``<AwhIURL_EX4CPveI%^0zVhCQoI4pf3(V{DYs` zRjYinp6|&fW$eJu%50$`U!?L__c+(!e%ZVr5rydS9`IQ2rKvExBy2wqehI{Yfc&wb zSRYfNACNw-AMKbvly=P;0UBB2v|?o6&t&s8`4{%xs*(K)<!4Io@E<Ps%ld*GEeowj z9GOh$7W|2q(&!hYO^z-?c_Rcr!Tn2KgEj<vOXbb?{^hCLq-janKI;JNpT`0&u@C5B z*<A27JPyG6w|mZL+B0{|Poa7>ioTALee$>XX;7>9^Kq;P97A@@9`((-zQqUswkbA> zOf{OJPgshEwQntUS-a<q5%h#(Fz5XX(Kin>z*-;JzQ2b2lH%n2jQ7|6fPV+}0qkR@ zwzd#_4#xn-fA9S9KZQ&*ioS<$GbOn~c}W=7=aapmjm7$GuGPHIdVZEXK9xIf9Pl4O z>Erqe>oTI9b@OfiJ@UThh3xP3HCV;|4*2t&;7y(r?q$W#g?b6&Q#)r4r@ad%P*(h; z5+}o!MSq5}qnBf$eCVl_%$~5NVXvvvh8J4T&yYoanfn$_6!eaLFXv&4!W}3)ug{0M z-j#^^{A^EQ>wCq<`)d~h|6c54*ayV=nhQQ4BW{SmPu8M1+P`=*?O#%IWC|MtA7YbI z{W`Q~QS4WF;O|Rf+?V@&(+73^Y8@rn_OF%&`DURV96LDw;yKwN4%))_9DMT!Urj}= zpM^c^1Mn}6dd{*B=w#ZImUech)REn3_pDI@_6HKC(SfBUM>Ymp|G-`f^RJA-mwM5% zk@7d|o-&}zKkoUm3~|oec{+Tvo|0_;Kgvp&3ZD}z^t(9j&kRJ)udkXH_Z!SB$(#?e z`05{YK$PDXh;cO#`U2Zy2UFI<Npx`O3_6rJv&6{N-0&Zm^$+nC%8wsDfWm-<ubl-Y zjUDpcIwzL^{&q$>->s)4+y8l4GX%ZcJ9nHg{<gAvE9!wb%(e(T?)zvd*92fc#qWQq z2+)D$90$S-8`0bld)gG!S;$A({tqvoLr0d+EfMmu`+VI*DH)j`E_YUB?|<kL+9lR^ zJYLv81n)d5p?3X9IfoNx2|kwNKKJ*>d1IbOPg$`2HX3s6eiint3&6iVbnZF#H+x#E z3v14|A|CBqFj2rid*yt}UbUdu6xHeP{xM@!tD0=F%2aP$^gW@=l_^6BW1@;xZ?R<o zd9p9qJ$sBW{~C|IQQ8|f$zR{OuW!4+ADZ7|EPwP5I?zjq1JJ=??uN8(Aoc~G5={pa zrqj{Y3+dR}Ma8CliL*bm&z6l;id|+iRi)3$MEeUpS8h;`_AH%U>^h4ji#74Y_LLPL zhdI{)!gD3PMH>12y}#OO$!q>7hQ+xL_zP<Uc}$4oz_dUcAr9=p*u;?)bLn{U5<0Oy z0kpJORI&WubEGboCdDc%pO^JB#*@fUm)N!o!{5ijx<u;Auk*)_33M!Zv0(c<rVSNr zY$$9^@cS5xX`|7gZ*edz?!C}~n(zU_m_R3UHClrHKpN&QSyzuiZ%=MWq*EK07mHdp z&fP<+c|#S-TCuQLWqrxZ`2Ib<ihoPQi7&7H)#oQSBnkS*w!dfYSi!cYVZRKvHMTj( zJ_Y#wl6>!5dICPop#$%EjYwbYeY^_uklQB>68Zvc|ED&upwp?Vewd=Wcc8(Y@Q&eP zlu_8ditz7f+h<f6>jsWN_J!T^tG++AX*q0vk<i~y!}^{@9o(p+X|w!%|C(=$dey&$ z%dh+mIuObI0rpEnT+k=Pa|oQL9$qm=u%k0uR@2$^wf`zgUp(_O+*uEJY+=K^DZiah zme+}tWkP?CV}4?{R@5DNcHaEXJIu)&|4MwnR~PV?0tsscc|2m6hY77897ellju3J| zZqK=G>;F~MvdKT!fXDRc^!s_-x=!$!hm&R#kFBog?N5EMKWzSbe$2&o_#Pg=<9FbX z=f>-A&CdtN_?TmEssnL8$T`f}^klk_xe>I9F6`L+TWP_#;h)()k0%cA)9ttN#Bw>G zv4PlDvRBQc9aCdyP5(d|;HdX^KVQ9m)bGGn+&Y1OMbJS(2aFoi#Mait&n57f)$w%+ zbZ+~4y0|lyF74Vvmv*Q9HtO9j=o9`j7*mR$H0rnUBFF*qV4L6=$zugOrwtRHwH=ID zn!lz4a-AkF4!`p{@X39GbNM<j&d&<-R2^y0ys^k<69gT<v^$+H@7+pQ_HO$v#PyfP zI)U=#%F@=vg};S|{I;_kSO?C*@AJ3`uc=vs=XeJ(_IYFbkm(B0_nzDTov?paH+WTq z4qVCCff3$$u>kW{tOFNzY!qakvp<u57mXU&n+~TY|F-(M-B+?Q=<=R)A?IMb=bU+E zzqZuhL9d|Q^E;UNeI0+)A9$_{9XOVs55#zw(mEk094X`joC|RKuO8e<*ADIe-=c%N z=<0zTf)8Z7=lKB6^^$tErrvhi1>^lf$nk4?b^Z~$0N$%W2X?RygkpVC1bo^G=y&E6 zjHj=hC+I!vz_r7B==zbpbR&D;|9j$gvc9w5=Uk8Hc=>sXh1e^kJH~ZC&FQGuANxmu z{2eBt17$&L^T!9cjSD(?3T@`LpGjLoSN3hE>xcK!&7=G2=CK2G^Z5TmLc4Bc?+5mK z5bx75HkyQWGZSd@u&xvvXh$8))N<ExXv*=scY1wCtbf$cXb-O+9RVHq$m4|E)(LHF z@yuFhp>M!r<J>2>4%yr~c93qJJWRJw9{K-4Cyvmq6NjPK`-NC{A!FmGJa6@YV2VOq z3`1WjZyx^<<mC28fm;M-(KcJegL~XoZu1~lBTDMi2G0@<CZ69um%fg!?%yH!fIFwM z>CWk6bob2hKa%d8IR^fZ3OdYo&-wnTO)G@C5q@5eePB-;Eg{F}_z1b|hkO)@AkIJX zQnayNeonx#u9Ia;niPO{Oktd0_w3QaydjSfa6DiiaQEy9x_9m*-8+Bk&miU%JhR@i z-CsklcYb?{Fel3M<E#1y(@-ySYG=|k-{13GPAsU@9|`CWFpaiyJcx!Kyx}oz_62>= z=ULFjJ8%9lmQHP0F7%B!CtyFo_}{;9h8|pGI{PoAGXj6CtL(d2e|b!Y$3A)8#>Syt zX>za=b+ytcX!ExrhyS<!{(Gu{wyQ!1wg|Z)_L*sq`K=f)Gg{WW4c0pJr~Qj23-d=; z_G}Yk!rimSb9La-IeK{c0zJBN@wXE5@bL0^dH{azpFb`5`x{60(ZwC9f*<2~TYgq@ zE_{7I?1L}FdES#zQ|>+59tYz682{)0Act1agBu(NIVN;4YfjOg=9JLOU(kcBg>k}s z7{>*cFZ%=b1%eJ-y+n_%Ue2X!SLpH2Ce-x^bw0|uC}7XHbDR?VJjU;N-2=~gq>ku8 zb2<WdCj)ASwOX9_vYw-zd(d9>|9Q~A5CCMta|fd!pJ$vOhUlsY{e&UNkK?=Iy{aR7 z3hT_XSIiT}$#b$Y>DKXsLagO@z<4nBPp)63CpU8G>CJ2OIbFy3_vrI`^2>U1Jx9<n z_BkAbIKFdUcNu*-UgL0R*$iR)E+x7X-dE^GePQp6JI~wY<#$)mzF^RAU$gOr=>Jux zkWW<*=LW*wL+lSYSL%)YU=sG>TrnU7&%6#0)|&Eo`PsC!0tP&;a_7`h_=VGgT^7^_ z)`4fYZsgMKoAj(O!Zo@2aZS)8_A6Wt`*+SiZlf>9V>j%FPH$c*jN5U}x&`~;Ebi5Y zM)`@TtF@-!=h@x^G=#kVTpsR!>^R=<P!Pzh5{UPpyUX^&^5ikZj^-`UZ#1Uq;qJ6z zV2H36&CVIaiPxU<nnRvLV|>^@@OUEo=6mN(<mQc+zsMVaE!*?MD~RJ)^5Qt+3g;QO zP8<@(BY14;Lgr>+td8}K*S2vUzj<U2O6b!TeHTaQroNE7@LV0|vw430IQaJi{W0@4 zzXRv*)d~6W9yIRIgVm7hTOmh)Pvv!RoG0|M*TXv+ZD@8Uyq^Gj^6_3M8F7(9&V69< z6k(j1$Cub%*;nv*JNL&fWMCZvuSLK-#QAM0!q@|k$MU)>)+2t7fwA5-bEL4IZ8PF| zV!t4o*3O-xy)393`tF>shUzyIbTiM#-v_T#LAu{-*MGkkT>_A6HBcw$!anH2$9%uQ zb{B5gM9_yGc=u?ehZ&7)V@K25dr*82f5A^AM|PwQF<oJ|J%v6dKd-=j41SJ|_cPl( zqC2g}b1Z9yw4)^S(HC^{r75AVf^J2)7*jX+bso25z2lg~cAkg%8`e$m<p%nn>BAQt zy^_5HvaSL0f$V34F0#*MJQx?wxp?lJvEm$z?Ua2*CySQU8U1gz-Cp*()Ynm;dfDj; zF}pL~LCCR%G3I<D+^C6gKkF8k$2qBhH~Ma<kH_jpfviEi$IgF$zgYsnK>-v58V7um zL8m}(gjme|u6+Ffj*KPi$tTLgHV@z2_?_EVdx|m+f|jD(Xpk$2_tX3D?+=gwu;O*8 zN+25$zt=nj)D08?LSIvEB96mA{Xv~U{O)THkSVD4AJD}ASo}`{|4HCK3H&F4|0M83 z5}@3_7>T?OxrZF=7+m0sk6g6*-(Ni8^D=**$ME^zB?y-nxZ#cPvqY8r8**~bKh+SE zd!AoF-tC_Xc%S#PghFlsLhbxr9tS!3zvmSglYcImdwu??ghVud@u~Q{3O*Gtky}9? zw|tkt@u%wYD$M!2JfXtOzt4pVWBxuDT2$ba87NS_z|d#s=0pY95g01Kj=)d>b_9mL zJkKdu9~jL1);SoCDfs)B=V(B|pBdxN&!azM9}W8A-2BV)&zc7WzBpI-^8B;rLjd19 z|4bYZ(D%-BK5tK%FV3Zld!8xr*`M@x&LzM2{oi)}5B_sLYo0{0<@G(hzVrKc_2WzZ z`BLA$bN&x~{!+icIFJ6)UcNa0!v0`iF$D$sr9I+2v*7PvvG1IMzr#a*b`FR3nE-MA znLrf2IRDZg!GC=wAo{|e;k;l2!R}`b68vS%-wX;4JoE2!!QbZmeXhXw7hqU8FTk)l z|6YKhXg>cN0ipT=3<=d2VCc*EAyi+WLIp0afJCB&)4waoJ^fT*Uh$tG$}9d;feQK8 z=W!gJf1WF{Pq*h`md6cWB;4@#<w6agO6LncO60YbPm1){#7aU!5fUeo7Knu}E6e}q z{x!kD0u%$16t2XFf6t#J?{~-hT{7Wa2c`1%KK%bS$0~`vy-MRfPF3(OuUh;b-@JD^ zso>o{>im8;kOkiHsEgm5;9Y+T{JuZPrVhXRhu{17Gxmi1nQFlNGT+QUw-s$OMB9S! zIod`fnj#WeFSM}{t-x_DXgw$e=j%YLMb_2{xMn6~Fb4Pa0NH~YfodBY8&~?7dn6WD zCfsg*Pb=D~44iG5f3#%=x6{_vI^E9BdY6N(b(XWp<fxmK(HT!my-U898rQrnwXe8a z8J>3$nVfVKSsZb&6J^=kiS|Gq8Mt=?%2|RkV?aKvGq9JMdGCe!SJ(=-8~9cLW-8#- z4}4Fzv9U_Av$f7}u{JsCYu@rkxM{;zoy?WqcQ(gf<mL+0-BJP1Mk{?7<lOMX06Ucr zJ*<>IcC%2RE@tx7*-YU>2Q!toZOqi}yIUEYx3{rAXlrA=3+1Ll2FpObAYUEmLXA9q zC@yqAdcP#=IomAS?GCJCZEbBfxmp>W@HcO9o7=!`9pt3?VMahRTH3KCt?H&h8~SKb z+CUxJHdu!;qjhQf5FJX#`KEr_w6>=vC3aS)d7)}F+_TZg9#)Ff$xP`(kXh45UKV<n zZEdU$LMOIE1_`LM3#g^LyL++U6;V_HFy^ScI@)dpUd8~M6lY7rW5K44o_9f;qg@+) zoD<xfl6z@VMwBjPjnk*>$p&<Mx*?sKZTNrXeFc0J#}_b^;>8`}LR>E{cex}Nce{8l zN=kqbBuIeZPARShid&H2u0;#91u97Y6l)6<*KoP_y|>98Cws{y(Eh&P_wDcZZgzKO zp3Kb7?#(=b-@fsH>nl9r=1NbvvC;#6Tjl}3Eb)NL3*6y{*=}%th8r9o;{tn%onTd- zEli0wmlgRL$@07mE8+xBw*vir&-wZJ9z@#9kOc{!&o``ZtfaciPGb&f_CWblkcTy4 z{@&-)yv!f><{QAI7<1XS{yaD~+7-@Cb4PhdJ}<blkq>`u6TpL=0{CaQ0G{mgfoBJN z;Q2uzlRn)igvWb);Neam_`6&H_saP2`x<ZfWvLfj_}T+bPH=;LL!Dt^x(yU!JLGs7 zzlj#Q-oWv82Kk^lVx&+gw8M8zbCl=bnim?<yBcZr#CGp5Lb{1w)_;BJZ73TZX)fE? zhX=>UdcaTf`EX;E0PbuOqP)KF^ngD+KkN@LkBQ**aesJoLIiKW6Tv%zQ&s8PlOpE+ zYs`CvWnLWdho=Yq;L#pGxWC00{<p>l+d=?mrg-9W;sUc%tf8-up-kdo`Z84Lc^P>+ zgzz=?3!k0`8lQFT*ILRm&pP(K6VjOw<nMDd!`<ZN0FkL|bv_S{lzPI&*#fw}$`Af3 z4}iz}0^!-AAe1=>UY`htHzyIk3qip2R4}|{0k7rfc#p}aGFbjK!mHy!*mgni<UkNS z+#LwF*89WdMM5|^5p6PyTwy}Ag)G;@pfW<>dJX4=6Uf^NoQtDqZbW%LSsPHlBVHcj zpB3io`F)OuQN@TbbJ@;;?r?6V5Pn@A0C%?p!=t^S@a#w!yf_vPFOMUf2!~fE5h$%I zRM#UsFA$y|4Ts13!{DzSA#h_&0Q@lD4-S`l!JHIZ$oDdUSZ{~BI1io1vAG_{K|Fnb ze2Qm*o_Cbp9N#$;qXf=Zay<-XQ{t^<`-giY4<fj=DGdJJ6$y_IM8VS|QOIXBJU_+) zUdzwfd-YGBA?_!KqTs>aNVvN-9DZ3I49Ca&z=|9m6bOuDi5`}Z0{s2XVn40M`5=(K znLefs$S*CnCB5H@BfWW-^E~unewrg39xa5+OM>C{)@XRJFBbke7zd9J$H9{$@ioH3 zL$NR-#~LE|I^bm40lXbLgIJ^wLozI(Y?^nCb>+B`&f`Pz@aRA++}{xczpV^|Q&at6 zV;?v4X=x%$b~AhG@9X;=^1KN9%>(<dzWe<2UDFxm&kYf{pU84Ekdf@iCy3zcvIw}n zEe`(PCq_OH4kp$L*^#CgdqCa)G4>Drjbwmg%Cv9Y6ogJ)VPb(JT-y?(886a(uwM-K zcE-cCHBoSOW)PGWdf_*eu`Jfp=1-LW7{UyE9&GaR^6ISLg6;MN)(s61dhd|98oZwp zYXe8eiQwmNqfvG-{JAFy<xhdX_ov_(NUjmWymaL<va)KMHf!1lqVSvI{I?NmG>G<J zdy?U9c@kV-7l&;S3afg#VJs~Ji1c>)9r-_qZ7>}Bum{r9`n^cw9_J4ee;=PYsV>H^ zN`ftA`%2KS;5RYw$JS)Hw<{Iy?@7}NruKEKx9qBI)U{&^7@A=Zw|Au|(?)*oY)^sT z)+E5m$sw>H%?Wib4P>D{?mwgaTX8N3v9+~riTJcSu<zSqz0?F3v%CF-J!R#Cgm7U& z4BXtD3b%J;z}=nNL%UX*eKjI8^=cdP>l@^*2e-=8<h<P3kq)=Eroq(}VmLe|2&TlL z-z_HtX@IYQ=ELbY7L1Tyt^QW4=X>iAZ`Z97Cp}ox%M;Fg9Sy&&O@;q$lfWO_2{N^U zYn#&RC7-tK(z1DDjN=hs&5HzXAzwF;<`0X-u(u=t|7V%X;@m9%M%n2bF|j(PWQ}70 z%XL8Lo#br%WK@W??8x|VxVkb8@n*u!vTXQ$OP1EKc$nY6DnGSTo0d)B+GdHIr<-M2 z@Y}i!I5#^EmS(!+7|@di`gmW&HduiF6D+8IH8lV|_xP+>g?Tz1%yKcnZ(1L?xG))h zTb~8jH|5j|x_A7vF_F2(MxmIe#M`wE*>L6C3^-64hOxygWMUWd$JnR45mNA5PNVG- z&G{l<-`EtM{>zDxc5rlJG+bGk1;4DzfnV3x4^Aykg~p$M_OFfu!)|TV`1^Tn4xF2l z1mEU*qu!V<ga|x-K>4TOcU*T({g3%wBHisaNqG9QE&cuB{QNYyvMLv@uKqYEn-GIB zENXuDbM>pX_d2(0$-!eD{J0GD>_<n!Fd73+CeQFaxB;I72Mx~veealKxqBrd3pg?{ z4laF@4L_~Os}U9s3V{@nHH5mGKuMYxoSc`zS$_Gj@PBO#7<F&QN%O}Qxo~=R8Z6E5 zMBP9gS%9zbAj+5+5fMS(#YzX>ZyDg@9hYjSQ@J439nQ?jfJ;krHA49$F_`pd$0<_; z#&zMU`)`eb!HMpi^e%mq3*Rrwf}KM`Art4pa8KT^*#F}xwzQJ)c!6WTLxj8S@^nW% z*|q@~D`S2(oL`iSkf#Q#hDT#8kDA}zx}Dpo)ob12(|-$m-sm$mI!Zh*%!R`f6JeO2 zg)G6j=M$8F4UKcvH3IzJ>xOZcuMG6*Dce6f9!}5AfioO%YIY9BCU3&o@7Rn=_owEG zlyJ0Z`RU}xk6Gxc(*b4`1S!$r;`#WDbeJu6A-~fyoZri_uif!or{tR|L@3lpUE6ol zqwxRTq*ORLGn*6mHu_33s>-Z*P5de1>DK<^-i4px9BQfG2@1kp(0(XG3AZ90)$`*s zvS4FD0NHTL!n~Z%qx?bmEz|;eWsioTJS!j69fcJVJ{+E$0Y|1t)Zox0Nv-1^5z5;~ zuTvW(9GU26SuwvZ=Z$fkuPKgI!pFrU=e@}iC@+qNd{=|YXgBK{_zWaeuMIHr(|1pd zlNssI!iM|+I4~{^4vbG%gTb+$b>hE7%vZv(Z)`erXx*YtIH--t&*!qjNF`ic{MB@C zS4jd4@G^op{7-}L!5n-C%6CiYS%`Bs8=2v#SGlPm81{@zhCQRy!PY>#`1Uk6#=2W@ z;wT%M0QxvC>eBaFe)gQWxOmibZ`bey7%nu0L?@Gfu>Xr_zGpfgf3Pi@#XFhK%X8M3 zZtfcjJBKB5LKBsk$6PXWXw@7R_0o)k#a$BX1y;J9plJ;_so#5{T@YJ`(rIb_Ouc4J zJ_mxfEt`SZ!xGAeBq)_rtV8EJh9$tb04qr08NNc<hv9cH#ob{J>i<NZ(VBi9MwOfU zN5b|YVl^lm9A9If(R>``Vy0G)3zzD>Wxc~e>}dsN-8+C$mv&&<tv$+Q1?!4pmGJpk zX`XxO+hQKZlvBkmzb;OIY2o&e;-FW7{oh})|LOV1*t5Hf`KGYBFdDWF605<;Sb;|Q zySHlv^Rq+M>Tuzy@4Xy9^_XJVc}hGr$MLWMW2$n|*fKC4X2rUoZLf|D*9VoJe;NcB ze{*ZGw<*R)jDjr#64W5fvC8kXoqiV>8N&yIPHn-kb32%pB2p{MRsUn}2`n}Dy<$7K z828}hr>rOr<##0;85#b^Rhs`9`5pA;_wzK7Zosj)xhP%@=4AzgkEH=@<jCVH|Ecc< z+8HbLwW7?5=Uv-=p~gG$vZ*i@rbh4})lvT)j{iW~yCu2VBhkTdL@!t4igmq$F)lCK zq<*BFQO@RI(W4{uXx|E)jk`nt5Vw!Qxw3bpR`Sy`z{UH<zA-Q^*cMWpjGp25uPe=Y ztn8E~IT%W^oDJTu&JJYa5|<4SW1Pae1I-i7(MK<$R0Eo;7v_Z53or3v(zW)u!t{TD zi|>tnqhW-fCD8v{ocnqre@gpfiOz<?bVq&J$}ADqPrx}Osm@Rmt$B`Q+oN^!rchQ7 z+{DlL#M;->I<;=8#`hMiyRmN+3=){j;+=b*$M=0#<VWd9wC`$w^25?pA;tzwh3&&6 zb%vJBwEJH)8Ex-b{H~^Y%y?;q?b5bobLif_HB8G0mFKhN*tGo@AL0t30BU2*%fe8t z?lz2Tv7sOedVBS(#P6K-ir>D9jezS!4<<)Cp%3qLCO$L8YSb2H_li~Hg^NGBH!Uj? zZJQ;~5&KG0nKYpjC+(t0AB}bByK~JTb>7Q|XTi#xAjrUVtr!=JZ0vu|HP940-9-Zg z7Sb&PlVLadc%)e2+Cs9>StDPHGB(Ee+dE2o!{9hkt>sG+@mrjOhmLKy|3`XQ7;%>0 zF(MnL$GFqn|JKLHMF;ueJWzg-#MwZ)_RB~H5BVg}7E=AS+vh2a_G54+`nc38{}=d7 zaM7RJCz-SEh7rBg%I}+4#5@m!e63_+N5kVaum3jqJe{Za>T9t#<NxZ=jG>?{3=)TM z@`Md7zi+PBU5-y+XD+|5SVr~y0NVO<@vwPxU&sjb0{ZTzIyOc+oaOdU8OX#r%ycoT zjB_^WP2aj$UgMF9KHH1^t)&$Ifa0{1&tq+1KgLdCc|qiAveBLum0@vt+iE92TV7Mj z(pp#APmY@{dt}x~Cg$k86d|NL=vM@I*ml+^cy&gqtxga<1FJD67{!UFIN{ntk4~E3 z&j#H(DdBOotcnlD^3RoifqwpLqJ0>B?o&N`Qv=R&<d>c1?;;;7DaP2|iDi}E`FPEF z;D3bEB|(l-@&R{p(L^Q&0>we74FcUXukVOO-tziK7Ea)dg^bK7jhjgY>GC?7Xt%|< zS6ikIQ!j@;`;W{T0Sht$$X>oO&e70@Q&^6h7?;!;{r1Sd&5vT@)l=+hiW6QN48<6~ zsxr_u{g2-?6=Mxo<0#Eb<t(RI*TPUwUY@PTl`bmj$64;w(y2@glRkV)X|jXfa>R{~ zr}js>eUGxiBD;6w^OfSGQ;g)=VAc4ca=E&9>HyXlv(m=Y5SES_s8rX-$xdDlIZ`|S z9N&@q7fe;EQyXoie2nFJV&Qn0o$62T{5LT?J+<}z+FBynM$d@$&zIo;dh&xwzV6BQ zdrfd2eF3xb99uq1V_A{Ale`>To=w}}c-}pKipIJ%(Wg9$VM+Z}J~9vW!ptjh&3jC3 zvTDjtbI=`|=h3rb)8KTupDK!nQxniU-=lM<8p}}qU~e~Q()e?wb}%#4hl^WR)>>C1 zee{1s@>A@w;lWN){GR<i&8~~qdLJC^&@kOWcUPg%=G|`evqOHg$j=h_&C>)F_jCE= zQjPhF^`;H|5XaHfKu@bWiuF~`$zK%3w4WR&kVza2Uc_7Jm~hBcr(5w>oxVtO)Vnr3 z)cHO64<rBY6cda5QE@?`1oZ_p<f-28(X}(v|IM2<#n^?Lw63R$hpw5J1gqx2!t8ML zdt)F?wC&+rCqZi{oMzj_FoS3CY*K=cjC`XKE%K2|{@OkUD27w3mM!7Cveh4fXAk2S zjQoDB>7RspPbTD}HNOUN>Xnt`pd-lO8NS1qIMQPn=ZT4bKyi>T4n}?9^o~vN3;L+5 zZ++Is9nJmA3S!akk?DK%T{x#+0%}ny*`^yWgQxdkNU(FozNy7b8&DjWI}``xKZYuQ zj(gzD@|o~;Mv#oY?^7N0hG`+jM-@rs>373<^-@1y+jm<>eaXy+6cdJte}I0&$#?j_ z3O}KLL-J9L@d%F18;5ox-tX~S?M<?M_y5cvwZy=n8Ga*g$n`L*n41~Kd>`Dv`G8`8 zkPk-kqyDLZ{K=C~Nb(O!@A>t`nJ_@)@D9Ii?<ZO7*nU)}*0VCc8}m_D=%0Q<yLaSw zj-Eq`4^`#Ql>8iD`)D8^xg`7Di)WZP1lz~;gOTAL6*S)Q`(#PHLs$7eRz1b|sA~9b zXo-A`LSJjI2L(94TRT|7d@J2NvA@dCFZy34U##SZm+|pSetv5K^506nddVL<%`ZP~ zTMc{A-`|9Ip%i_?$xuh7Jk_?l*+(({i7Qh-(A+C=HG1D0zn75L$_>Nw@LO~?^KPR# zfqV~>pLvpv#s=fV6n&9XA3wN$mFed{uU=$iCV$ksCJ#p6^I<SB(CHod#KZmRQ)#w3 zuAi9oPl^t|x!R}N_DIig(A$yiYVtN;VEw){+VlO~oCsJoC<C^R=?D8~j=~r^Gnn}3 z<SYKjyz#JO(qLFOESK>II$7)|!x$S?GV}DWVC>WpX|}r7pOn%609m}dPIDZm5$X22 z-$<Mc&S$$A-_Le6eMdeD$+zK`0vjpgw-9|D=D7E)%yKpPC)3&RXKcHjsdnA_BwBaZ z{SVmu&q+w^4cewSbhS*wZ&aK+oamhzA78s}_J7Xk{|5xo>A>46j|J#|p_E(@px*|@ zN5N5CF`;W}1WXuT27+p@3i{Q~5wIW@W1J3+rW7kMDORA%4}N7zt9>U3s#E=HZxC$S zrrKKsn>M{gwULus_=88&Tlj+q>&HYjW&N$l)6q=v1`V}Mk5-qjC6&{?RaL%Gb=p)l zRgs7FZ^Fu}uhJf+)!r}Iw7UJ+_Cy~OM;qXQ?adIv9%Be#KQIl6{lXw91*Rg?Z&-op zM=XfNm;#hw4SoD!kM*Vv8W<qvDnAlc+d`^-B<wL?g3ypDi6{T^L2LBn6N2`r$@Y-+ zlL+XX?p5c}I)0tj^!`P*8Gjble6~gX0teJF3&(xt40HrA0QF7A1o-<;!0Td!Y|M{A z@WOrg&ZLJ(@*r<otxbPo85o;h;sf~-`3r?3(5ATz?d^{T2l|}~6$!qN_V>6P=jU`S z*5BpVNPn*%(MQ2q@=riE`Dk-WHu=*~r#>E2qiUUs|3Z$2WbaLUV>@ReA6r92!c%d+ z&et;e=1=?h7)pyohLyuYOr&FCdP=7zT2xMqGp`&OVJaOQXe>n=>dJg?<G0Ct+xwAz zo|jRUQ;6dL;zIfTdREKvZ;h?byu7^HAssQ=t8R?+b-$eB-ScIU$f$Bkf<@(O^b@du z7}-)g!>LIwaDIA~?fiwAu5fmWE1Vqf!uSo?KEMGMW?0Ee!c3)T`}sbFZ}WGsNO&Io z5Kx~KAq_oE`@HoXLxd08$QWtN4)yiAkm+sqd{}5t+%H92k<l)2VJ6!4FZY7m8~AV^ zZP@?X#z&iWvU&G`N4wDey_^q!Zso(>O?<TJ_JYgvJ>c|YH`rb5jBC}_l?6UVQnA3{ zPGErOG`7zsfk5C*&s2T+RjfyI2eylw$j^6U3g7y{zyK5Jid=iNt@ngqm-(QLKH01L zq20DWydqom69H(Gj)1o5Z@&v*Y}T3U;{j;LE`pawMeukp+NW>xga54+!lgOhuzQFr zOii$=%;y_dL<rq~K^gWV|0&h_2K63K)CTyBMFjc@4rO_ozM3YssXUA}=T{c_!kx_l z@MM25JU<eG_U56;cPR4ALKvQ_LRH>tEc5C_2-<3gppAJ5${qwa*NEWUS3YP*>WqE{ zOr&uF-XAE#G1M0uhCH-YY)@^^={d!A_X+j!I@Qa|sA6%ZqwLHKU-*4J(%cil*fT#r zN_Nsw$V=UU>JdCc+v~>%BH-S(F!*^{AnY0D3By7xq$%Fkk8n;y{~@A6oG<FM7EbRW zl;1W);CZ;0x3P3xfh$~?69l)*qTu0vvO`9j=fi08%mGIh`lB6h7vQ6fv%gDMv{&p7 zF+yFKJ<tj6?nXOqjyjL=-aiN8;IG}WXxAJLN5=TV_!yhY6nFEd*oH@t7jYe)hlXhH zri(T$8*<!@E7pAJ20ttagWFr;;qSdk$UnjXZt$}2qEXMCbWE`Caqr?YurzE7L(nJ1 zon7J&xDf9Hgg<vB!nM`WjJ<S8h@~{%+wMN{zaRTSfHH9EpD2zgdN1PpXh?>;>C5@) zPO|UkMxgC&65K~y*FX1YhWr>yjl2`zszCA(SQ@s2)nk1>;NFe4r8}x@YWI!sLt9ES zX$0T-I?AvL`6vGh8V|B9!7|ojH_JQYqwFeAP78+{8&eqD**j=ITN9A}8X~S2kQ_~$ zG=lOOA#xgjY)gmB%i>{6kpS0+jiiA>{&}3k(`Y`_Bmg}pL41$-xgN&S{iA~5=hdlb zUzrL2+nQA)9Gt7Y4pdDt(ta`7j#kkln^p;YKOgmXlbmHqZj3D>`cw*_|Hf)_Dm}9} zU-6P%%^uB7b%9HZli}J%?d&%%uaV%mZd9+fSCxlsRTOPTe_1PmLu0}r-`hkQ#P_^} z&p|#{AJDx}FXt)wsEd1WY$V$CRoP#X4W>4*eryD@->%9}eXh?eN&7$(?I|xTN`plb z4@hw_d4bQtYA!uG@`07?Y<h2g3i|Pxk7I9TZk^$)zWz1p(r6<KJqxq?2Po10X?YGD z8W#h3?#9w!AJ21W2WP8j2S(@q0)bN+PfxlF?G-OB$w3>)JSDiWBoAT*=1d#o;A8AM z$*ya|=vbw4ZNF&tQR9ek@1K#Xgp=&~&d!y<q)2;NjJwTke2#M!#}NHDigdG^QOGxY ze{5O`oL_+Uduacr2wl)tlyIxIAw6@8287AWS{qjFO{$jD=9=&ubZslgrAYtW{2W-* z+YeHChHvnlwjew_TyBR&@3v$Y(~DolIm3ysGU3#$Y$Xu;Sab5u@?_ehgS>n^#sgvR zYm*Ys)CN5|wt`}@ryP$e4|KhEWGvu%o-{zn--A4Vf%ut&{x{%W@r$*+{Nd<S2^^i4 zDTl*TGHZP<$)1I+GbYWqMp==dTt4DG+S5W_m&KteJvcrE2K$&v(H`^)@=Shmn1kkh z+|#JoQWy&R$E7MkajXaO|A8h}kkhAg;vv?<LSAR@m{c&=>8O<q(HH|rm0pe4V^dI< z-3FrFZEhmZhDaaDH)s&f<8{O}^7m!^BVcC<+At}Ajh^Q5OgbAmA_t}NY~4tgo<RAU zWDm4Ame(ssdig;-h{ty58|o~-&*D-{r$u2oSBpRK8Fr+17V#hF(9=5G+2Gxl0nupB zBvyiED!L+AoM~IKFIe4Ay}WAuuTT#x2zl+;ss(gI8wqza9q1G6ET>Tr=){aql9T$9 zfNY9}M|;W3DB_$ab_bm2ALBD@!_J{eJOkg}ZpLrR&~8c928Y3k?MQqRkREWhucKNy z)q2`omkrQtn?-%MFgHw%&XN>9q&gYB#OGHB`C-OSqP-!nm#fk1&4n>aHZ*Jd#6VO0 zE*O^}ge7_5P>6BkKGvQ`vHqf*FnPPM?W34_ndvIgD?{6q1xenJ=3@E;zmw&0Z6Y1a zx@Doh*ZSTOXvc*%JavG{7y~ih)e_RZ?Vv#93>)iEm*|jvsv^&d=Z0u2rOZnl%#3k` zBp35P6z5M`2g^Vm?REKKXu~2#NYn~Edg@h;SsJ_5&+6x&eFhW6{#w;1IwD&Wjr{9% zY@>{)e*#Plb%X>ri__I>MJO(FG(`P~C#&;9VC#@Hg!Eb=KfsmY9c!!6Z;H=6i=!mY z7ZN?~AWh&1r3wD>`)vN2q9o2airOO&X|Uy(6zw}o{B0^@oy`|luRT_?-=IMzPw&jU zWC4)Q{Em^iwL*thnr#^9*&`exdozXpsgg6s!%hvitzmbyHX#1DtMEbgDZSiG-iuu= zN#}uic3A;Z>~;GL^S61oYxI|#wg9U31YGUT-ZSdfk-@=UtERqoW=b?RU>rl@SFxNi z>OHH{T-PU>baK%a;lsBB)?tn$2fglShxM|2cs9nk8^px9qgZ#Efc|G-MKz##eB-Fz zuzl<Y9Xr)>q-Uy%w|9guv_yS0w(P?G5~VVv5Bs%PfOC)WG1ald2!KBlC;i`6^ol_J z@e<TQ9$6!FXw7ZQ;c98Z)LT8GfOA|Ee<Zsm{FJZPrK4ItwP}C8`MV@X<9L=|)s*zd z2K!pQJdFDKq(@s52zl1>wj!DY^sd|U)d;5E)PgjP{5NmfL?dn*M=M75Rm!J$sq6ZS z>D%)ue(T7;n^pPu@oDh6gr|3Jb-#E<FZ}fK8K4P<O5)YVZ2Q)&<mC;zbKAVr_?lLj zEib2vKRwh>Esyl^2l(2&OLZ_PP~}<m8to8b`|-_R97i3eb8F_JZp}PS*f4cORhwgb zwZ*xpONVx_Y1$}x*+v}iCF&nbBlIb!0Vmge(kWimH=gvV@8H0x(T0ST1?SSMi*mzd z->+K$mo_isgbNrK8_R>2gDq!%$F^;h-VemPz{#GotR@<yFGX!%;AQqQ*;Y4<<*&9h z-L6N^EN8=~TT0NE(6*JR`?`)3nlx?<I~Gjm%%eKJ5@Y1g2%T%f!*&1ij<rDXU`xYY z-%1?yH`K<nYJQ4c_kdm=#?KGWDuti-Zf10MNq<)n3epmlt`+m>T;x?{+r@X`)mToo z9>p~N33amPWCTfZPW&kz*TPl#)8-oE-3`L$=J}~_ro%OiRe$ruzB+-mnJKtC+SjQL z>GhI+^~ypq;QQz=)bpy<cBm#<P^V>TAHK!&12ad!&6E3qbS6o+>)!y<!6QBGd6}V7 z)Tg<h=Ge`mCf>BoOR>{Q&2cw*ws}N8{QlhmMkkNa`~2~ImHy{Prldc4`}^-0J^OJn zp06@_`j?V;-D_NH)|Pj+9O;i?n>?B#_I-PH)m*su6Y6YM>!p!yTD_oJH<QNY7PQOj z%eQ<kanN0rSGBLrlKy0AmRZME5=Y(XIc_G;7Uajgzr14|BSV#5-F0~U$IaRS<A*cx z;Zg67^l1;y9t}f+9G~M@zfO8dpN!cW5G6Y3cE@+b`aBPl=M&=uuXju?#(3A8;o-HP z8UCN#{-2WGBwe$y?MeUnH0sVRD@>6M@V9xA<z)01>P4m^Ii>I68pwaLEQyst*EBo5 zyc`$f@3P&DUlfb%pH5E>c(b%`5^O5%3wvjlLOIH|dPok;&54qZjrM%e$IJXlmW$B? ze7`J6w$bJP-=hCT`mD)zx`Al>l$YsbI5x+{aBYsO@$np2qutpqM)UFgKM?2Rq$E2% zt54Q|{|_KS#iXi0IIJ2O>LuxulF_YdHKe1AmKdWSCRZyf{h+qQ=tBuq)XP{kCrlB| z2lXdb9ZEH2)un1nQQK)W;nS4XQ2!`Z!+a)Hpnr?*v+7xFs=z;^rltQuU5k}hQEdy^ z`OrQ{fN4-fjA)pO`joQm3rCU4hhshN&Kn>LReD^cPNW_W$N=y8AT(r3;>o8yn3xc_ z9^08+&-}FLm9f!(XA$~1_xJamfVw-og8T#*!i1hzLwvoj1o-)UkGeJc@ct}ZpNu7* zlxx@j3in%DV|<fBr1e9t$mZeDQ1jR0Vk|1Ai7nsH%dnQtO0|+sPOz*P9c}(@K(NKj zRDZ`i=!5tY?w3tOUi9iuxj_Tc0SOnnUn~r;cr_=@MtWeR6Y9{o!>x6m7$?CS9_-*_ z{0P#o@rIkLFm}XDH`qGB5p6^)D{}p;A0r<ZkdMN;_7Ar8=Yb;Oh#X(5Cts!5N>5F} zm=>EUK7$B#M^GQ;L?Fg72!wa1gD|E;5bB%+q7F?U#&8Hgy%K+n2O&g#3^y1VX;~o_ zI+0GvLehcKvMm~-|K7QM{4HN?9qcB%xi%Oc?8bNiq$_ef5@QSyL~#P;6FfZ}iN4~) z;L4H!n49h(l?ZJgAP<|k)?ZY4!abhizP=W34viJUt<6#B?>!#%KE&wnK0yw7(WcO@ zbrWdUstNuFZ35QDZDGj>H+lZ!Ls%B;{Jl3Gep?j|tNXagGWb@sc0Pw)J6EMk*Qhh- zohz_>v1cU4z}O^4U+3iSJXHz!4&6A{7ij%}{O)#c*BtsMTEn$X2~55FyHTfMbsQ|r zbd@Gx%mm~ii;Fh#mF#8n%c=rz*>7u6ccEN@`U{zApsjD;M(F$A+PDK#|Bvk%=%YFg z#zZ>24-$A@z<yBs#trfDN+}Moes^(E65QCFg^;ZV7gnU9Pkqhn&M24se<z*Oe`i~h zP7I!F8#CeX_z1}Mws?+XVYq4=q`I45+g==q`|sKC^V(dEP@L+<tV5~N(sWHeyIFic zF3*H%NiNb*zUxKBwKRdJdxyS4t2bxoro)fRbLB9*FaYBNG>1-YTR@~&Px*aKerUOP zXxXf>yxtGXa$(<ST#IzKc#8W_E^He_x!Dwbo$Mh!i+i=_7F5Atu?Mpc#^R*5w81@M z%1`#QQEF$ljABabMUBzdU$1bU94FQNZk7c4_*lM09j!u^e!8p4@lE|h;rR4SIdJ(N zr1fzsGc8x7wuYrhyA}Ft9g^UMd$J$!vAB<6{V8#-(ok=gWi0(n7vme-2S>xcF)0j` zCh^stF<RSpGwUHQW2M(gseM@bM0>}`BzZX&r((J=oexnS4u@I#*{;TSwhoMi@}al~ zh+vJlS$vdII}VQYkms}IhDLdSIr<Q6(X=rGIvrZU`T?=9s$V2@Yxf0E8@59qTv@($ zN_CfI`a*)c^-nDQJXfPTWdq~nduDCWZ*ME~?L>6RXQL(`dz$v@h^8X{v~D{&8TT-% z{S1Da69_48=9gLexh_W6HuZ~vvZ4eACMWsH&)IvF4h(gN!QmdT9M_r^@2j3W8}(44 zPrL-#naJxbO818(H_L-8ecXdRzp)@1whT<-gw?nX*b>)nX^v&)S)7AP<Aj`L3CHMo zq1xC8ap);8KPOQDv2NDWS^7CndW%-}3WxHNY)%l`sP9#gFR7uizDyreKehj&1#BFg zA+N9KldTc%jjbJ+CeIre<tB~gnebWqxc<$X66gJf{GV_^YqasFHe`X?Al1(mTDMT{ zXS!zV4;2T?+n_!2%HF5Fk$jJyXr!Qg^z$;kc4+!g#s>}gp-}{DLmfG7;(^xDDW6ih zW`Wv4vEK5bxlG>l-pTU&TZd%>{trE-Ouaz^?1KgC2BykRE}n!j7L=hVDMC(zWG_yO zf#c}Yr7_yGv$QE~f%_<`b&Yy-Rk}AW#_MgmgN}nLee8qQg?#f{wB~ni)odl$h`v+^ zf3qe{fc%V5{>(x7N^{_6*vB&m_EM@x<&G?wD!;d9(g4VDHc*qD<t2xwSF*Hs>|3%$ zR0YC+0oSzI`x~Z@ftJmiGxH?vD~&J2_ZCMz_TB~b6*4T4_YmbYV(D?E*blpQOdKF1 zp96}}H$745n(`(LEMVGY>BNz0d5U#ujb&zf@QW;-u7r!G;yvWAS)Pl*g+p`4$!N{5 zCMYc`fQdtjYAi!`(#s1|-eB8mZKsbsw8`e_9osg(=<VH$r{V4oXX^#D?m8na_@8W^ z?ifWGwK+!~KErzRCnfs-`2*VHKD_>m*6`QQKf<AT6Do^@RyQ&obwA2ZoyJS9lit3s zvm+m#SoXDy)?c6hc~1?V-M<Ytj_rk=Ge*209_n%%+xsi5t8vdvn>J7^gSd2X{FL-^ z);l#c$nn~gw2*sC2S^?*=$rgte1h+tB7w!#JSV-~84fyPEL$hNb45DZo+FLM2zm&e z5%BY@eg{YexVV8U4>-TbFwQ$I<KW~>c6m*2Asnr;!6Q4khNHCuD$7FCTZp3?pFZLy zd%#kn#n43B`KTFg(131GT;r<k5><P&wwO<4>bj0W`l`WxzOLckPQ%0aE<-UMgeU&@ zAapezq+==ewBFRu&-~RaiB-j}Qpd`z!yPK8rCL_x3wpkc^5!kq^j|X6-O(Y()9m4q zDXub#cliEv0K7j_4R}trBxS>Rm8tF)_e6Y8M@2^Xj@C{4`I$Zb-zKz^I1&#}kH*95 zaUS5q>jEL3-C<O&4V?T&#N=IB9s-$O=6@>cQ>M6@?>R9mLZ%q6$;+-AGe;sFCZ(8U z?lxWF!YcHeJW5m<?P0&3c)&5#VrGud+v{8U!1b~|uzXYmTwH~|)RJ74>JuLNwqH0j z6yxv|puU*%Yg%7GKdV9I6EkF2Hw=ZOfGXe3VO~~nW?6s6Z#PT7eVZ20KS=;oj^LX? zG4I2@U7gZhOcozoFcfxtJ&^H})T2{7{7;<?7uSr3vH7tWJI)L|>`Y<fl)f;dC<WF| z=*{GnPwGQH?o03+ZrzE+6JXWYB3LxMHyp)%{L{;)qQ8)-aCXHsIV{FJdWY+xuE2NS zOom<PZ!po>bOb)P3ERdGkg@yPd*_S=W1Vj3+o=Prn@|j;dC9PO%5bbR4QP*?{8k;9 zKLM5w%6cz$FtDd*amDb0*R=mfuy{<BZ!m)%-C*J9V*KCQ2>7^<OL=og41^ee0dqb* zPy7Pwenx#TDA?u4Uk{cu`*v3`HPP3DaRd9oz&r`l2f0b{@;$xpcW#7B<!dqio7HZr zO9$f7Upn;5r{qV0VCR}|nRNHMl@RPFgxi<SGS`$xeg`IIME;F+<oc|H1Lw_L+)sb{ z<n}H39Q*X%9r-!Uy$^5x3X2BkKf<|PKy_4)RQn#5<5GivxpHKW^vS*3P+1{`%6Ap; z2=`#V-?_PBSh(j&q}xTcp5is;H$vd!J80bCV5h_AlWI?vqi!+Yb5bnFp1;-KEWFip cv+!u6&BD<QtDr%H%|b3<^QkP=d5U%a59OI8(EtDd literal 0 HcmV?d00001 diff --git a/MiniAssembler/unit1.lfm b/MiniAssembler/unit1.lfm new file mode 100644 index 0000000..637ca93 --- /dev/null +++ b/MiniAssembler/unit1.lfm @@ -0,0 +1,55 @@ +object Form1: TForm1 + Left = 265 + Height = 368 + Top = 159 + Width = 530 + Caption = 'Form1' + ClientHeight = 368 + ClientWidth = 530 + OnCreate = FormCreate + OnDestroy = FormDestroy + LCLVersion = '1.8.0.6' + object Memo1: TMemo + Left = 10 + Height = 312 + Top = 40 + Width = 190 + Lines.Strings = ( + 'LDA' + 'STA $10' + ) + TabOrder = 0 + end + object Button1: TButton + Left = 216 + Height = 25 + Top = 40 + Width = 88 + Caption = 'Assemble>>' + OnClick = Button1Click + TabOrder = 1 + end + object Memo2: TMemo + Left = 320 + Height = 312 + Top = 40 + Width = 190 + TabOrder = 2 + end + object Label1: TLabel + Left = 10 + Height = 15 + Top = 10 + Width = 31 + Caption = 'CODE' + ParentColor = False + end + object Label2: TLabel + Left = 328 + Height = 15 + Top = 10 + Width = 46 + Caption = 'HEX FILE' + ParentColor = False + end +end diff --git a/MiniAssembler/unit1.pas b/MiniAssembler/unit1.pas new file mode 100644 index 0000000..7ca83f1 --- /dev/null +++ b/MiniAssembler/unit1.pas @@ -0,0 +1,186 @@ +{Sample of how to create a very basic assembler tool, using the unit pic16utils.} +unit Unit1; +{$mode objfpc}{$H+} + +interface +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, + P6502utils; + +type + { TForm1 } + + TForm1 = class(TForm) + Button1: TButton; + Label1: TLabel; + Label2: TLabel; + Memo1: TMemo; + Memo2: TMemo; + procedure Button1Click(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + private + pic: TP6502; + function CaptureComma(var lin: string): boolean; + function ExtractNumber(var lin: string; out num: word): boolean; + function ExtractString(var lin: string; var str: string): boolean; + end; + +var + Form1: TForm1; + +implementation +{$R *.lfm} +{ TForm1 } + +function TForm1.ExtractString(var lin: string; var str: string): boolean; +var + tmp: String; + i: Integer; +begin + Result := true; + lin := trim(lin); //trim + if lin='' then begin + Application.MessageBox('Expected identifier.',''); + Result := false; + exit; + end; + tmp := ''; + i:=1; + while lin[i] in ['a'..'z','A'..'Z'] do begin + tmp += lin[i]; + inc(i); + end; + lin := copy(lin,i,100); + lin := trim(lin); //trim + str := tmp; + if str = '' then begin + //No string found + exit(false); + end; +end; +function TForm1.ExtractNumber(var lin: string; out num: word): boolean; +var + tmp: String; + i: Integer; +begin + Result := true; + lin := trim(lin); //trim + if lin='' then begin + Application.MessageBox('Expected number.',''); + Result := false; + exit; + end; + tmp := ''; + i:=1; + while lin[i] in ['$','0'..'9','x','X'] do begin + tmp += lin[i]; + inc(i); + end; + lin := copy(lin,i,100); + lin := trim(lin); //trim + if LowerCase( copy(tmp,1,2)) = '0x' then + num := StrToInt('$' + copy(tmp,3,100)) + else + num := StrToInt(tmp); +end; +function TForm1.CaptureComma(var lin: string): boolean; +begin + Result := true; + lin := trim(lin); //trim + if lin='' then begin + Application.MessageBox('Expected comma.',''); + Result := false; + exit; + end; + if lin[1]<>',' then begin + Application.MessageBox('Expected comma.',''); + Result := false; + exit; + end; + lin := copy(lin,2,100); + lin := trim(lin); //trim +end; + +procedure TForm1.Button1Click(Sender: TObject); +var + l: String; + idInst: TP6502Inst; + Inst: String; + stx, lin, Par: String; + n: word; +begin + pic.iRam:=0; //Start to code at $0000 + pic.MsjError:=''; //Clear error + for lin in Memo1.Lines do begin + l := lin; //crea copia para modificar + if trim(l) = '' then continue; + if not ExtractString(l, Inst) then begin //extract mnemonic + Application.MessageBox('Syntax Error',''); + exit; + end; + //Find mnemonic, and parameters + idInst := pic.FindOpcode(Inst); + if idInst = i_Inval then begin + Application.MessageBox(PChar('Invalid Opcode: '+ Inst),''); + exit; + end; + //Extract parameters + if l = '' then begin + //No parameters. Must be Implicit + pic.codAsmFD(idInst, aImplicit , 0); + if pic.MsjError<>'' then begin + Application.MessageBox(PChar(lin + ':' + pic.MsjError),''); + exit; + end; + end else if ExtractString(l, Par) then begin //extract mnemonic + //It's a string + if Par = 'A' then begin + //Accumulator mode + pic.codAsmFD(idInst, aAcumulat , 0); + if pic.MsjError<>'' then begin + Application.MessageBox(PChar(lin + ':' + pic.MsjError),''); + exit; + end; + end else begin + Application.MessageBox(PChar(lin + ': Syntax error' ),''); + end; + end else if ExtractNumber(l, n) then begin + //There is a number + if n<256 then begin + //Zero page. Although could be ,X + pic.codAsmFD(idInst, aZeroPage , 0); + if pic.MsjError<>'' then begin + Application.MessageBox(PChar(lin + ':' + pic.MsjError),''); + exit; + end; + end else begin + //Absolute. Although could be ,X + pic.codAsmFD(idInst, aAbsolute , 0); + if pic.MsjError<>'' then begin + Application.MessageBox(PChar(lin + ':' + pic.MsjError),''); + exit; + end; + end; + end else begin + //Not a string, nor a number, nor empty + Application.MessageBox('Syntax Error',''); + exit; + end; + end; + pic.GenHex(Application.ExeName + '.hex'); + Memo2.Lines.LoadFromFile(Application.ExeName + '.hex'); +end; + +procedure TForm1.FormCreate(Sender: TObject); +begin + pic := TP6502.Create; +end; + +procedure TForm1.FormDestroy(Sender: TObject); +begin + pic.Destroy; +end; + +end. + diff --git a/P6502utils.pas b/P6502utils.pas new file mode 100644 index 0000000..b799179 --- /dev/null +++ b/P6502utils.pas @@ -0,0 +1,1446 @@ +{ +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, PicCore; +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 + aIdxIndir, //Indexed Indirect: LDA ($40,X) Only for X + aIndirIdx //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; + + //Indica el destino de la instrucción + TPIC16destin = ( + toW = %00000000, //al acumulador + toF = %10000000 //a memoria + ); + + + +const //Constants of address and bit positions for some registers + _STATUS = $03; + _C = 0; + _Z = 2; + _RP0 = 5; + _RP1 = 6; +// _IRP = 7; +type + {Objeto que representa al hardware de un PIC de la serie 16} + { TP6502 } + TP6502 = class(TPicCore) + public //Campos para desensamblar instrucciones + idIns: TP6502Inst; //ID de Instrucción. + modIns: TP6502AddMode; //Modo de direccionamiento + parIns: word; //Parámetro de instrucción. Válido solo en algunas instrucciones. + b_ : byte; //Bit destino. Válido solo en algunas instrucciones. + k_ : word; //Parámetro Literal. Válido solo en algunas instrucciones. + private //Campos para procesar instrucciones + function GetINTCON: byte; + function GetINTCON_GIE: boolean; + function GetSTATUS: byte; + function GetSTATUS_C: boolean; + function GetSTATUS_DC: boolean; + function GetSTATUS_IRP: boolean; + function GetSTATUS_Z: boolean; + procedure SetINTCON_GIE(AValue: boolean); + procedure SetSTATUS_C(AValue: boolean); + procedure SetSTATUS_DC(AValue: boolean); + procedure SetSTATUS_IRP(AValue: boolean); + procedure SetSTATUS_Z(AValue: boolean); + procedure SetFRAM(value: byte); + function GetFRAM: byte; + public //Campos que modelan a los registros internos + W : byte; //Registro de trabajo + PC : TWordRec; //PC as record to fast access for bytes + PCLATH : byte; //Contador de Programa H + STKPTR : 0..7; //Puntero de pila + STACK : array[0..7] of word; + property STATUS: byte read GetSTATUS; + property STATUS_Z: boolean read GetSTATUS_Z write SetSTATUS_Z; + property STATUS_C: boolean read GetSTATUS_C write SetSTATUS_C; + property STATUS_DC: boolean read GetSTATUS_DC write SetSTATUS_DC; + property STATUS_IRP: boolean read GetSTATUS_IRP write SetSTATUS_IRP; + 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; override; + function ReadPC: dword; override; + procedure WritePC(AValue: dword); override; + public //Memories + procedure Decode(const opCode: word); //decodifica instrucción + 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 + ): string; override; + public //Funciones para la memoria RAM + function GetFreeByte(out addr: word; shared: boolean): boolean; + function GetFreeBytes(const size: integer; var addr: word): boolean; //obtiene una dirección libre + function TotalMemRAM: word; //devuelve el total de memoria RAM + function UsedMemRAM: word; //devuelve el total de memoria RAM usada + procedure ExploreUsed(rutExplorRAM: TPICRutExplorRAM); //devuelve un reporte del uso de la RAM + 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 + procedure useRAM; + procedure codAsmFD(const inst: TP6502Inst; addMode: TP6502AddMode; param: word); + function codInsert(iRam0, nInsert, nWords: integer): boolean; + public //Métodos adicionales + function FindOpcode(Op: string): TP6502Inst; //busca Opcode + procedure GenHex(hexFile: string; ConfigWord: integer = - 1); //genera un archivo hex + procedure DumpCode(lOut: TStrings; incAdrr, incCom, incVarNam: boolean); //vuelva en código que contiene + public //Initialization + constructor Create; override; + destructor Destroy; override; + end; + +var //variables globales + //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.useRAM; +{Marca la posición actual, como usada, e incrementa el puntero iRam. Si hay error, +actualiza el campo "MsjError"} +begin + //Protección de desborde + if iRam >= CPUMAXRAM then begin + MsjError := 'RAM Memory limit exceeded.'; + exit; + end; + ram[iRam].used := true; //marca como usado + inc(iRam); +end; +procedure TP6502.codAsmFD(const inst: TP6502Inst; addMode: TP6502AddMode; param: word); +{Codifica las instrucciones orientadas a registro, con sintAxis: NEMÓNICO f,d} +var + rInst: TP6502Instruct; +begin + rInst := PIC16InstName[inst]; + //Write OpCode + ram[iRam].value := rInst.instrInform[addMode].Opcode; + useRAM; //marca como usado e incrementa puntero. + //Codifica parámetros + 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 + useRAM; + end; + aAbsolute:begin + ram[iRam].value := lo(param); + useRAM; + ram[iRam].value := hi(param); + useRAM; + end; + aZeroPage:begin + ram[iRam].value := lo(param); + useRAM; + end; + aRelative:begin + ram[iRam].value := lo(param); + useRAM; + end; + aIndirect:begin + ram[iRam].value := lo(param); + useRAM; + ram[iRam].value := hi(param); + useRAM; + end; + aAbsolutX:begin + ram[iRam].value := lo(param); + useRAM; + ram[iRam].value := hi(param); + useRAM; + end; + aAbsolutY:begin + ram[iRam].value := lo(param); + useRAM; + ram[iRam].value := hi(param); + useRAM; + end; + aZeroPagX:begin + ram[iRam].value := lo(param); + useRAM; + end; + aZeroPagY:begin + ram[iRam].value := lo(param); + useRAM; + end; + aIdxIndir:begin + ram[iRam].value := lo(param); + useRAM; + end; + aIndirIdx:begin + ram[iRam].value := lo(param); + useRAM; + end; + else + raise Exception.Create('Implementation Error.'); + end; +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; +{Busca una cádena que represente a una instrucción (Opcode). Si encuentra devuelve + el identificador de instrucción . Si no encuentra devuelve "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 encontró + Result := i_Inval; +end; +//Campos para procesar instrucciones +function TP6502.GetSTATUS: byte; +begin + Result := ram[_STATUS].dvalue; +end; +function TP6502.GetSTATUS_Z: boolean; +begin + Result := (ram[_STATUS].dvalue and %00000100) <> 0; +end; +procedure TP6502.SetSTATUS_Z(AValue: boolean); +begin + if AVAlue then ram[_STATUS].dvalue := ram[_STATUS].dvalue or %00000100 + else ram[_STATUS].dvalue := ram[_STATUS].dvalue and %11111011; +end; +function TP6502.GetSTATUS_C: boolean; +begin + Result := (ram[_STATUS].dvalue and %00000001) <> 0; +end; +procedure TP6502.SetSTATUS_C(AValue: boolean); +begin + if AVAlue then ram[_STATUS].dvalue := ram[_STATUS].dvalue or %00000001 + else ram[_STATUS].dvalue := ram[_STATUS].dvalue and %11111110; +end; +function TP6502.GetSTATUS_DC: boolean; +begin + Result := (ram[_STATUS].dvalue and %00000010) <> 0; +end; +procedure TP6502.SetSTATUS_DC(AValue: boolean); +begin + if AVAlue then ram[_STATUS].dvalue := ram[_STATUS].dvalue or %00000010 + else ram[_STATUS].dvalue := ram[_STATUS].dvalue and %11111101; +end; +function TP6502.GetSTATUS_IRP: boolean; +begin + Result := (ram[_STATUS].dvalue and %10000000) <> 0; +end; +procedure TP6502.SetSTATUS_IRP(AValue: boolean); +begin + if AVAlue then ram[_STATUS].dvalue := ram[_STATUS].dvalue or %10000000 + else ram[_STATUS].dvalue := ram[_STATUS].dvalue and %01111111; +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 +} +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; + end; + end; + end; +end; +function TP6502.Disassembler(const opCode, par1, par2: byte; + out nBytesProc: byte; + useVarName: boolean = false): string; +{Disassemble the instruction indicated in "Opcode". If the instruction is multibyte +it will be used "par1" and "par2" according to the intruction length, which is 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; + f: word; +begin + Decode(opCode); //Decode instruction. Update: "idIns", "modIns". + nemo := trim(PIC16InstName[idIns].name) + ' '; + case modIns of + aImplicit: begin + nBytesProc := 1; //No parameters needed + end; + aAcumulat: begin + nBytesProc := 1; //No parameters needed + end; + aImmediat: begin + Result := nemo + '#$'+IntToHex(par1,2); + nBytesProc := 2; + end; + aAbsolute: begin + Result := nemo + '$'+IntToHex(par1 + par2*256, 4); + nBytesProc := 3; + end; + aZeroPage: begin + Result := nemo + '$'+IntToHex(par1, 2); + nBytesProc := 2; + end; + aRelative: begin + Result := nemo + '$'+IntToHex(par1, 2); + nBytesProc := 2; + end; + aIndirect: begin + Result := nemo + '$('+IntToHex(par1 + par2*256, 4)+')'; + nBytesProc := 3; + end; + aAbsolutX: begin + Result := nemo + '$'+IntToHex(par1 + par2*256, 4)+',X'; + nBytesProc := 3; + end; + aAbsolutY: begin + Result := nemo + '$'+IntToHex(par1 + par2*256, 4)+',Y'; + nBytesProc := 3; + end; + aZeroPagX: begin + Result := nemo + '$'+IntToHex(par1, 2)+',X'; + nBytesProc := 3; + end; + aZeroPagY: begin + Result := nemo + '$'+IntToHex(par1, 2)+',Y'; + nBytesProc := 3; + end; + aIdxIndir: begin + Result := nemo + '$('+IntToHex(par1, 2)+',X)'; + nBytesProc := 2; + end; + aIndirIdx: begin + Result := nemo + '$('+IntToHex(par1, 2)+'),Y'; + nBytesProc := 3; + 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; +{Resturn 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; + msk, resNib: byte; + nCycles, nBytes: byte; + resInt : integer; +begin + //Decodifica instrucción + opc := ram[aPC].value; + Decode(opc); //Decode instruction + nCycles := PIC16InstName[idIns].instrInform[modIns].Cycles; + nBytes := PIC16InstName[idIns].instrInform[modIns].nBytes; + + case idIns of + 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 + i_Inval: begin + MsjError := 'Invalid Opcode'; + end; + end; + +{ i_ADDWF: begin + resByte := FRAM; + resWord := W + resByte; + resNib := (W and $0F) + (resByte and $0F); + if modIns = toF then begin + FRAM := resWord and $FF; + end else begin //toW + w := resWord and $FF; + end; + STATUS_Z := (resWord and $ff) = 0; + STATUS_C := (resWord > 255); + STATUS_DC := (resNib > 15); + end; + i_ANDWF: begin + resByte := W and FRAM; + if modIns = toF then begin + FRAM := resByte; + end else begin //toW + w := resByte; + end; + STATUS_Z := resByte = 0; + end; + i_CLRF: begin + FRAM := 0; + STATUS_Z := true; + end; + i_CLRW: begin + W := 0; + STATUS_Z := true; + end; + i_COMF : begin + resByte := not FRAM; + if modIns = toF then begin + FRAM := resByte; + end else begin //toW + w := resByte; + end; + STATUS_Z := resByte = 0; + end; + i_DECF : begin + resByte := FRAM; + if resByte = 0 then resByte := $FF else dec(resByte); + if modIns = toF then begin + FRAM := resByte; + end else begin //toW + w := resByte; + end; + STATUS_Z := resByte = 0; + end; + i_DECFSZ: begin + resByte := FRAM; + if resByte = 0 then resByte := $FF else dec(resByte); + if modIns = toF then begin + FRAM := resByte; + end else begin //toW + w := resByte; + end; + STATUS_Z := resByte = 0; + if STATUS_Z then begin + Inc(PC.W); //Jump one instrucción + Inc(nClck); //In this case it takes one more cicle + end; + end; + i_INCF: begin + resByte := FRAM; + if resByte = 255 then resByte := 0 else inc(resByte); + if modIns = toF then begin + FRAM := resByte; + end else begin //toW + w := resByte; + end; + STATUS_Z := resByte = 0; + end; + i_INCFSZ: begin + resByte := FRAM; + if resByte = 255 then resByte := 0 else inc(resByte); + if modIns = toF then begin + FRAM := resByte; + end else begin //toW + w := resByte; + end; + STATUS_Z := resByte = 0; + if STATUS_Z then begin + Inc(PC.W); //Jump one instrucción + Inc(nClck); //In this case it takes one more cicle + end; + end; + i_IORWF: begin + resByte := W or FRAM; + if modIns = toF then begin + FRAM := resByte; + end else begin //toW + w := resByte; + end; + STATUS_Z := resByte <> 0; + end; + i_MOVF: begin + resByte := FRAM; + if modIns = toF then begin + //no mueve, solo verifica + STATUS_Z := (resByte = 0); + end else begin //toW + w := resByte; + STATUS_Z := (resByte = 0); + end; + end; + i_MOVWF: begin + FRAM := W; //escribe a donde esté mapeado, (si está mapeado) + if parIns = $02 then begin //Es el PCL + PC.H := PCLATH; //Cuando se escribe en PCL, se carga PCH con PCLATH + end; + end; + i_NOP: begin + end; + i_RLF: begin + resByte := FRAM; + bit7 := resByte and $80; //guarda bit 7 + resByte := (resByte << 1) and $ff; //desplaza + //pone C en bit bajo + if STATUS_C then begin //C era 1 + resByte := resByte or $01; //pone a 1 el bit 0 + end else begin //C era 0 + //no es necesario agregarlo, porque por defecto se agrega 0 + end; + //Actualiza C + if bit7 = 0 then STATUS_C := false + else STATUS_C := true; + if modIns = toF then begin + FRAM := resByte; + end else begin //toW + w := resByte; + end; + end; + i_RRF: begin + resByte := FRAM; + bit0 := resByte and $01; //guarda bit 0 + resByte := resByte >> 1; //desplaza + //pone C en bit alto + if STATUS_C then begin //C era 1 + resByte := resByte or $80; //pone a 1 el bit 0 + end else begin //C era 0 + //no es necesario agregarlo, porque por defecto se agrega 0 + end; + //Actualiza C + if bit0 = 0 then STATUS_C := false + else STATUS_C := true; + if modIns = toF then begin + FRAM := resByte; + end else begin //toW + w := resByte; + end; + end; + i_SUBWF: begin + resByte := FRAM; + resInt := resByte - W; + if modIns = toF then begin + FRAM := resInt and $FF; + end else begin //toW + w := resInt and $FF; + end; + STATUS_Z := (resInt = 0); + if resInt < 0 then STATUS_C := false //negativo + else STATUS_C := true; + resInt := (resByte and $0F) - (W and $0F); + if resInt < 0 then STATUS_DC := false //negativo + else STATUS_DC := true; + end; + i_SWAPF: begin + resByte := FRAM; + FRAM := (resByte >> 4) or (resByte << 4); + end; + i_XORWF: begin + resByte := W xor FRAM; + if modIns = toF then begin + FRAM := resByte; + end else begin //toW + w := resByte; + end; + STATUS_Z := resByte <> 0; + end; + //BIT-ORIENTED FILE REGISTER OPERATIONS + i_BCF: begin + msk := $1 << b_; + msk := not msk; + FRAM := FRAM and msk; + end; + i_BSF: begin + msk := $1 << b_; + FRAM := FRAM or msk;// b_ + end; + i_BTFSC: begin + msk := $1 << b_; + if (FRAM and msk) = 0 then begin + Inc(PC.W); //Jump one instrucción + Inc(nClck); //In this case it takes one more cicle + end; + end; + i_BTFSS: begin + msk := $1 << b_; + if (FRAM and msk) <> 0 then begin + Inc(PC.W); //Jump one instrucción + Inc(nClck); //In this case it takes one more cicle + end; + end; + //LITERAL AND CONTROL OPERATIONS + i_ADDLW: begin + resWord := W + k_; + resNib := (W and $0F) + (k_ and $0F); + w := resWord and $FF; + STATUS_Z := (resWord and $ff) = 0; + STATUS_C := (resWord > 255); + STATUS_DC := (resNib > 15); + end; + i_ANDLW: begin + resByte := W and K_; + w := resByte; + STATUS_Z := resByte = 0; + end; + i_CALL: begin + //Guarda dirección en Pila + STACK[STKPTR] := PC.W; + if STKPTR = 7 then begin + //Desborde de pila + STKPTR := 0; + if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on CALL OpCode at $' + IntToHex(aPC,4)); + end else begin + STKPTR := STKPTR +1; + end; + 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 + Inc(nClck,2); //This instruction takes two cicles + exit; + end; + i_CLRWDT: begin + end; + i_GOTO: begin + 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 + Inc(nClck,2); //This instruction takes two cicles + exit; + end; + i_IORLW: begin + resByte := W or k_; + w := resByte; + STATUS_Z := resByte <> 0; + end; + i_MOVLW: begin + W := k_; + end; + i_RETFIE: begin + //Saca dirección en Pila + if STKPTR = 0 then begin + //Desborde de pila + STKPTR := 7; + if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on RETFIE OpCode at $' + IntToHex(aPC,4)); + end else begin + STKPTR := STKPTR - 1; + end; + PC.W := STACK[STKPTR]; //Should be 13 bits + Inc(nClck); //Esta instrucción toma un ciclo más + //Activa GIE + INTCON_GIE := true; + end; + i_RETLW: begin + //Saca dirección en Pila + if STKPTR = 0 then begin + //Desborde de pila + STKPTR := 7; + if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on RETLW OpCode at $' + IntToHex(aPC,4)); + end else begin + STKPTR := STKPTR - 1; + end; + PC.W := STACK[STKPTR]; //Should be 13 bits + Inc(nClck); //Esta instrucción toma un ciclo más + //Fija valor en W + W := k_; + end; + i_RETURN: begin + //Saca dirección en Pila + if STKPTR = 0 then begin + //Desborde de pila + STKPTR := 7; + if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on RETURN OpCode at $' + IntToHex(aPC,4)); + end else begin + STKPTR := STKPTR - 1; + end; + PC.W := STACK[STKPTR]; //Should be 13 bits + Inc(nClck); //Esta instrucción toma un ciclo más + end; + i_SLEEP: begin + end; + i_SUBLW: begin + resInt := k_ - W; + w := resInt and $FF; + STATUS_Z := (resInt = 0); + if resInt < 0 then STATUS_C := false //negativo + else STATUS_C := true; + resInt := (k_ and $0F) - (W and $0F); + if resInt < 0 then STATUS_DC := false //negativo + else STATUS_DC := true; + end; + i_XORLW: begin + resByte := W xor k_; + w := resByte; + STATUS_Z := resByte <> 0; + 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 not ram[_pc].used 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; +//Reinicia el dipsoitivo +var + i: Integer; +begin + PC.W := 0; + PCLATH := 0; + W := 0; + STKPTR := 0; //Posición inicial del puntero de pila + nClck := 0; //Inicia contador de ciclos + CommStop := false; //Limpia bandera + //Limpia solamente el valor inicial, no toca los otros campos + for i:=0 to high(ram) do begin + ram[i].dvalue := $00; + end; + ram[_STATUS].dvalue := %00011000; //STATUS +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; shared: boolean): boolean; +{Devuelve una dirección libre de la memoria RAM. +"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: word; +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:=0 to maxRam-1 do begin + if (ram[i].state = cs_impleGPR) and (not ram[i].used) then begin + //Esta dirección está libre + ram[i].used := true; //marca como usado + 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; + end; + end; +end; +function TP6502.GetFreeBytes(const size: integer; var addr: word): boolean; +{Devuelve una dirección libre de la memoria RAM para ubicar un bloque + del tamaño indicado. Si encuentra espacio, devuelve TRUE. + El tamaño se da en bytes, pero si el valor es negativo, se entiende que es en bits.} +var + i: word; + maxRam: Word; +begin + Result := false; //valor por defecto + if size=0 then exit; + maxRam := CPUMAXRAM; + for i:=0 to CPUMAXRAM-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 + addr := i; + Result := true; //indica que encontró espacio + exit; + end; + end; +end; +function TP6502.TotalMemRAM: word; +{Devuelve el total de memoria RAM disponible} +var + i: Integer; +begin + Result := 0; + for i := 0 to CPUMAXRAM - 1 do begin + if ram[i].AvailGPR 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].AvailGPR and (ram[i].used) then begin + //Notar que "AvailGPR" asegura que no se consideran registros maepados + Result := Result + 1; + end; + end; +end; +procedure TP6502.ExploreUsed(rutExplorRAM: TPICRutExplorRAM); +{Genera un reporte de uso de RAM} +var + i: Integer; +begin + for i := 0 to CPUMAXRAM - 1 do begin + if ram[i].AvailGPR and (ram[i].used) then begin + rutExplorRAM(i, 0, @ram[i]); + end; + end; +end; +function TP6502.ValidRAMaddr(addr: word): boolean; +{Indica si la dirección indicada es válida dentro del hardware del PIC} +begin + if addr > CPUMAXRAM then exit(false); //excede límite + exit(true); +end; +procedure TP6502.GenHex(hexFile: string; ConfigWord: integer = -1); +{Genera el archivo *.hex, a partir de los datos almacenados en la memoria RAM. +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. + Se debe llamar despues de llamar a GenHex(), para que se actualicen las variables} +var + i: Word; + lblLin, comLat, comLin, lin: String; + nBytes: byte; +begin + //Se supone que minUsed y maxUsed, ya deben haber sido actualizados. + i := minUsed; + while i <= maxUsed do begin + //Lee comentarios y etiqueta + lblLin := ram[i].topLabel; + comLat := ram[i].sideComment; + comLin := ram[i].topComment; + //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 + lin := DisassemblerAt(i, nBytes, incVarNam); //Instrucción + i := i + nBytes; + //Verificas si incluye dirección física + if incAdrr then begin + lin := '0x'+IntToHex(i,3) + ' ' + lin; + end; + //Verifica si incluye comentario lateral + if incCom then begin + lin := lin + ' ' + comLat; + end; + lOut.Add(' ' + lin); + end; +end; +constructor TP6502.Create; +begin + inherited Create; + //Default hardware settings + CPUMAXRAM := 4096; //Máx RAM memory + SetLength(ram, CPUMAXRAM); + //inicia una configuración común + ClearMemRAM; + SetStatRAM($020, $04F, 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(aIdxIndir,$61,2,6,''); + PIC16InstName[i_ADC].AddAddressMode(aIndirIdx,$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(aIdxIndir,$21,2,6,''); + PIC16InstName[i_AND].AddAddressMode(aIndirIdx,$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(aIdxIndir,$C1,2,6,''); + PIC16InstName[i_CMP].AddAddressMode(aIndirIdx,$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(aIdxIndir,$41,2,6,''); + PIC16InstName[i_EOR].AddAddressMode(aIndirIdx,$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(aIdxIndir,$A1,2,6,''); + PIC16InstName[i_LDA].AddAddressMode(aIndirIdx,$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(aIdxIndir,$01,2,6,''); + PIC16InstName[i_ORA].AddAddressMode(aIndirIdx,$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(aIdxIndir,$E1,2,6,''); + PIC16InstName[i_SBC].AddAddressMode(aIndirIdx,$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(aIdxIndir,$81,2,6,''); + PIC16InstName[i_STA].AddAddressMode(aIndirIdx,$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 := 'Inval'; + + +end; +initialization + InitTables; +end. //1550