1 {
2 Description
3 ===========
4 Utilities for programming Mid-range PIC microcontrollers with 14 bits instructions.
5 Include most of the PIC16 devices.
6 This unit works with 2K words pages and 128 bytes RAM banks.
7 The main class TPIC16 must model all devices of this family, including the most complex.
8 The aim of this unit is to be used as base for assemblers, compilers and simulators.
9 
10                                          Created by Tito Hinostroza   26/07/2015
11 }
12 
13 unit Pic16Utils;
14 {$mode objfpc}{$H+}
15 interface
16 uses
17   Classes, SysUtils, LCLProc, PicCore;
18 type  //Mid-range PIC instructions
19   TPIC16Inst = (
20     //BYTE-ORIENTED FILE REGISTER OPERATIONS
21     i_ADDWF,
22     i_ANDWF,
23     i_CLRF,
24     i_CLRW,
25     i_COMF ,
26     i_DECF ,
27     i_DECFSZ,
28     i_INCF,
29     i_INCFSZ,
30     i_IORWF,
31     i_MOVF,
32     i_MOVWF,
33     i_NOP,
34     i_RLF,
35     i_RRF,
36     i_SUBWF,
37     i_SWAPF,
38     i_XORWF,
39     //BIT-ORIENTED FILE REGISTER OPERATIONS
40     i_BCF,
41     i_BSF,
42     i_BTFSC,
43     i_BTFSS,
44     //LITERAL AND CONTROL OPERATIONS
45     i_ADDLW,
46     i_ANDLW,
47     i_CALL,
48     i_CLRWDT,
49     i_GOTO,
50     i_IORLW,
51     i_MOVLW,
52     i_RETFIE,
53     i_RETLW,
54     i_RETURN,
55     i_SLEEP,
56     i_SUBLW,
57     i_XORLW,
58     //INVALID INSTRUCTION
59     i_Inval
60   );
61   //Indica el destino de la instrucción
62   TPIC16destin = (
63     toW = %00000000,    //al acumulador
64     toF = %10000000     //a memoria
65   );
66 
67 
68 
69 const  //Constants of address and bit positions for some registers
70   _STATUS = $03;
71   _C      = 0;
72   _Z      = 2;
73   _RP0    = 5;
74   _RP1    = 6;
75 //  _IRP   = 7;
76 type
77   {Objeto que representa al hardware de un PIC de la serie 16}
78   { TPIC16 }
79   TPIC16 = class(TPicCore)
80   public  //Campos para procesar instrucciones
81     idIns: TPIC16Inst;    //ID de Instrucción.
82     d_   : TPIC16destin;  //Destino de operación. Válido solo en algunas instrucciones.
83     f_   : byte;          //Registro destino. Válido solo en algunas instrucciones.
84     b_   : byte;          //Bit destino. Válido solo en algunas instrucciones.
85     k_   : word;          //Parámetro Literal. Válido solo en algunas instrucciones.
86   private //Campos para procesar instrucciones
GetBanknull87     function GetBank(i : Longint): TPICRAMBank;
GetINTCONnull88     function GetINTCON: byte;
GetINTCON_GIEnull89     function GetINTCON_GIE: boolean;
GetPagenull90     function GetPage(i : Longint): TPICFlashPage;
GetSTATUSnull91     function GetSTATUS: byte;
GetSTATUS_Cnull92     function GetSTATUS_C: boolean;
GetSTATUS_DCnull93     function GetSTATUS_DC: boolean;
GetSTATUS_IRPnull94     function GetSTATUS_IRP: boolean;
GetSTATUS_Znull95     function GetSTATUS_Z: boolean;
96     procedure SetINTCON_GIE(AValue: boolean);
97     procedure SetSTATUS_C(AValue: boolean);
98     procedure SetSTATUS_DC(AValue: boolean);
99     procedure SetSTATUS_IRP(AValue: boolean);
100     procedure SetSTATUS_Z(AValue: boolean);
101     procedure SetFRAM(value: byte);
GetFRAMnull102     function GetFRAM: byte;
103   public  //Campos que modelan a los registros internos
104     W        : byte;   //Registro de trabajo
105     PC       : TWordRec; //PC as record to fast access for bytes
106     PCLATH   : byte;   //Contador de Programa H
107     STKPTR   : 0..7;   //Puntero de pila
108     STACK    : array[0..7] of word;
109     property STATUS: byte read GetSTATUS;
110     property STATUS_Z: boolean read GetSTATUS_Z write SetSTATUS_Z;
111     property STATUS_C: boolean read GetSTATUS_C write SetSTATUS_C;
112     property STATUS_DC: boolean read GetSTATUS_DC write SetSTATUS_DC;
113     property STATUS_IRP: boolean read GetSTATUS_IRP write SetSTATUS_IRP;
114     property INTCON: byte read GetINTCON;
115     property INTCON_GIE: boolean read GetINTCON_GIE write SetINTCON_GIE;
116     property FRAM: byte read GetFRAM write SetFRAM;
117   public  //Execution control
CurInstructionnull118     function CurInstruction: TPIC16Inst;
119     procedure Exec(aPC: word); override; //Ejecuta la instrucción en la dirección indicada.
120     procedure Exec; override; //Ejecuta instrucción actual
121     procedure ExecTo(endAdd: word); override; //Ejecuta hasta cierta dirección
122     procedure ExecStep; override; //Execute one instruction considering CALL as one instruction
123     procedure ExecNCycles(nCyc: integer; out stopped: boolean); override; //Ejecuta hasta cierta dirección
124     procedure Reset; override;
ReadPCnull125     function ReadPC: dword; override;
126     procedure WritePC(AValue: dword); override;
127   public  //Memories
128     procedure Decode(const opCode: word);  //decodifica instrucción
Disassemblernull129     function Disassembler(const opCode: word; bankNum: byte = 255;
130       useVarName: boolean = false): string;  //Desensambla la instrucción actual
DisassemblerAtnull131     function DisassemblerAt(addr: word; useVarName: boolean = false): string; override;
132     property banks[i : Longint]: TPICRAMBank Read GetBank;
133     property pages[i : Longint]: TPICFlashPage Read GetPage;
134   public  //RAM memory functions
GetFreeBitnull135     function GetFreeBit(out addr: word; out bit: byte; shared: boolean): boolean;
GetFreeBytenull136     function GetFreeByte(out addr: word; shared: boolean): boolean;
GetFreeBytesnull137     function GetFreeBytes(const size: integer; var addr: word): boolean;  //obtiene una dirección libre
TotalMemRAMnull138     function TotalMemRAM: word; //devuelve el total de memoria RAM
UsedMemRAMnull139     function UsedMemRAM: word;  //devuelve el total de memoria RAM usada
140     procedure ExploreUsed(rutExplorRAM: TPICRutExplorRAM);    //devuelve un reporte del uso de la RAM
ValidRAMaddrnull141     function ValidRAMaddr(addr: word): boolean;  //indica si una posición de memoria es válida
BankToAbsRAMnull142     function BankToAbsRAM(const offset, bank: byte): word; //devuelve dirección absoluta
143     procedure AbsToBankRAM(const AbsAddr: word; var offset, bank: byte); //convierte dirección absoluta
144   public  //Métodos para codificar instrucciones de acuerdo a la sintaxis
145     procedure useFlash;
146     procedure codAsmFD(const inst: TPIC16Inst; const f: word; d: TPIC16destin);
147     procedure codAsmF(const inst: TPIC16Inst; const f: word);
148     procedure codAsmFB(const inst: TPIC16Inst; const f: word; b: byte);
149     procedure codAsmK(const inst: TPIC16Inst; const k: byte);
150     procedure codAsmA(const inst: TPIC16Inst; const a: word);
151     procedure codAsm(const inst: TPIC16Inst);
152     procedure codGotoAt(iflash0: integer; const k: word);
153     procedure codCallAt(iflash0: integer; const k: word);
codInsertnull154     function codInsert(iflash0, nInsert, nWords: integer): boolean;
155     procedure BTFSC_sw_BTFSS(iflash0: integer);
156   public  //Métodos adicionales
FindOpcodenull157     function FindOpcode(Op: string; out syntax: string): TPIC16Inst;  //busca Opcode
158     procedure GenHex(hexFile: string; ConfigWord: integer = - 1);  //genera un archivo hex
159     procedure DumpCode(lOut: TStrings; incAdrr, incCom, incVarNam: boolean);  //vuelva en código que contiene
160   public  //Initialization
161     constructor Create; override;
162     destructor Destroy; override;
163   end;
164 
165 var  //variables globales
166   //mnemónico de las instrucciones
167   PIC16InstName: array[low(TPIC16Inst)..high(TPIC16Inst)] of string[7];
168   //sintaxis en ensamblador de las instrucciones
169   PIC16InstSyntax: array[low(TPIC16Inst)..high(TPIC16Inst)] of string[5];
170 
171 implementation
172 
173 { TPIC16 }
174 procedure TPIC16.useFlash;
175 {Marca la posición actual, como usada, e incrementa el puntero iFlash. S ihay error,
176 actualiza el campo "MsjError"}
177 begin
178   //Protección de desborde
179   if iFlash >= MaxFlash then begin
180     MsjError := 'FLASH Memory limit exceeded.';
181     exit;
182   end;
183   flash[iFlash].used := true;  //marca como usado
184   inc(iFlash);
185 end;
186 procedure TPIC16.codAsmFD(const inst: TPIC16Inst; const f: word; d: TPIC16destin);
187 {Codifica las instrucciones orientadas a registro, con sinatxis: NEMÓNICO f,d}
188 begin
189   case inst of
190   i_ADDWF : flash[iFlash].value := %00011100000000 + ord(d) + (f and %1111111);
191   i_ANDWF : flash[iFlash].value := %00010100000000 + ord(d) + (f and %1111111);
192   i_COMF  : flash[iFlash].value := %00100100000000 + ord(d) + (f and %1111111);
193   i_DECF  : flash[iFlash].value := %00001100000000 + ord(d) + (f and %1111111);
194   i_DECFSZ: flash[iFlash].value := %00101100000000 + ord(d) + (f and %1111111);
195   i_INCF  : flash[iFlash].value := %00101000000000 + ord(d) + (f and %1111111);
196   i_INCFSZ: flash[iFlash].value := %00111100000000 + ord(d) + (f and %1111111);
197   i_IORWF : flash[iFlash].value := %00010000000000 + ord(d) + (f and %1111111);
198   i_MOVF  : flash[iFlash].value := %00100000000000 + ord(d) + (f and %1111111);
199   i_RLF   : flash[iFlash].value := %00110100000000 + ord(d) + (f and %1111111);
200   i_RRF   : flash[iFlash].value := %00110000000000 + ord(d) + (f and %1111111);
201   i_SUBWF : flash[iFlash].value := %00001000000000 + ord(d) + (f and %1111111);
202   i_SWAPF : flash[iFlash].value := %00111000000000 + ord(d) + (f and %1111111);
203   i_XORWF : flash[iFlash].value := %00011000000000 + ord(d) + (f and %1111111);
204   else
205     raise Exception.Create('Implementation Error.');
206   end;
207   useFlash;  //marca como usado e incrementa puntero.
208 end;
209 procedure TPIC16.codAsmF(const inst: TPIC16Inst; const f: word);
210 {Codifica las instrucciones orientadas a registro, con sinatxis: NEMÓNICO f}
211 begin
212   case inst of
213   i_CLRF  : flash[iFlash].value := %00000110000000 + (f and %1111111);
214   i_MOVWF : flash[iFlash].value := %00000010000000 + (f and %1111111);
215   else
216     raise Exception.Create('Implementation Error.');
217   end;
218   useFlash;  //marca como usado e incrementa puntero.
219 end;
220 procedure TPIC16.codAsmFB(const inst: TPIC16Inst; const f: word; b: byte);
221 //Codifica las instrucciones orientadas a bit.
222 begin
223   case inst of
224   i_BCF  : flash[iFlash].value := %01000000000000 + word(b<<7) + (f and %1111111);
225   i_BSF  : flash[iFlash].value := %01010000000000 + word(b<<7) + (f and %1111111);
226   i_BTFSC: flash[iFlash].value := %01100000000000 + word(b<<7) + (f and %1111111);
227   i_BTFSS: flash[iFlash].value := %01110000000000 + word(b<<7) + (f and %1111111);
228   else
229     raise Exception.Create('Implementation Error.');
230   end;
231   useFlash;  //marca como usado e incrementa puntero.
232 end;
233 procedure TPIC16.codAsmK(const inst: TPIC16Inst; const k: byte);
234 {Codifica las instrucciones con constantes.}
235 begin
236   case inst of
237   i_ADDLW : flash[iFlash].value := %11111000000000 + k;
238   i_ANDLW : flash[iFlash].value := %11100100000000 + k;
239   i_IORLW : flash[iFlash].value := %11100000000000 + k;
240   i_MOVLW : flash[iFlash].value := %11000000000000 + k;
241   i_RETLW : flash[iFlash].value := %11010000000000 + k;
242   i_SUBLW : flash[iFlash].value := %11110000000000 + k;
243   i_XORLW : flash[iFlash].value := %11101000000000 + k;
244   else
245     raise Exception.Create('Implementation Error.');
246   end;
247   useFlash;  //marca como usado e incrementa puntero.
248 end;
249 procedure TPIC16.codAsmA(const inst: TPIC16Inst; const a: word);
250 {Codifica las instrucciones de control.
251  "a" debe ser word, porque la dirección destino, requiere 11 bits.}
252 begin
253   case inst of
254   i_CALL  : flash[iFlash].value := %10000000000000 + (a and %11111111111);
255   i_GOTO : flash[iFlash].value := %10100000000000 + (a and %11111111111);
256   else
257     raise Exception.Create('Implementation Error.');
258   end;
259   useFlash;  //marca como usado e incrementa puntero.
260 end;
261 procedure TPIC16.codAsm(const inst: TPIC16Inst);
262 //Codifica las instrucciones de control.
263 begin
264   case inst of
265   i_CLRW  : flash[iFlash].value := %00000100000000;
266   i_NOP   : flash[iFlash].value := %00000000000000;
267   i_CLRWDT: flash[iFlash].value := %00000001100100;
268   i_RETFIE: flash[iFlash].value := %00000000001001;
269   i_RETURN: flash[iFlash].value := %00000000001000;
270   i_SLEEP : flash[iFlash].value := %00000001100011;
271   else
272     raise Exception.Create('Implementation Error.');
273   end;
274   useFlash;  //marca como usado e incrementa puntero.
275 end;
276 procedure TPIC16.codGotoAt(iflash0: integer; const k: word);
277 {Codifica una instrucción GOTO, en una posición específica y sin alterar el puntero "iFlash"
278 actual. Se usa para completar saltos indefinidos}
279 begin
280   flash[iFlash0].value := %10100000000000 + (k and %11111111111);
281 end;
282 procedure TPIC16.codCallAt(iflash0: integer; const k: word);
283 {Codifica una instrucción i_CALL, en una posición específica y sin alterar el puntero "iFlash"
284 actual. Se usa para completar llamadas indefinidas}
285 begin
286   flash[iFlash0].value := %10000000000000 + (k and %11111111111);
287 end;
TPIC16.codInsertnull288 function TPIC16.codInsert(iflash0, nInsert, nWords: integer): boolean;
289 {Inserta en la posición iflash0, "nInsert" palabras, desplazando "nWords" palabras.
290 Al final debe quedar "nInsert" palabras de espacio libre en iflash0.
291 Si hay error devuelve FALSE.}
292 var
293   i: Integer;
294 begin
295   Result := True;  //By default
296   if iFlash+nInsert+nWords-1> MaxFlash then begin
297     //Overflow on address
298     exit(false);
299   end;
300   for i:= iflash + nInsert + nWords -1 downto iFlash + nWords do begin
301     flash[i] := flash[i-nInsert];
302   end;
303 end;
304 procedure TPIC16.BTFSC_sw_BTFSS(iflash0: integer);
305 {Exchange instruction i_BTFSC to i_BTFSS, or viceversa, in the specified address.}
306 begin
307   //Solo necesita cambiar el bit apropiado
308   flash[iFlash0].value := flash[iFlash0].value XOR %10000000000;
309 end;
FindOpcodenull310 function TPIC16.FindOpcode(Op: string; out syntax: string): TPIC16Inst;
311 {Busca una cádena que represente a una instrucción (Opcode). Si encuentra devuelve
312  el identificador de instrucción y una cadena que representa a la sintaxis en "syntax".
313  Si no encuentra devuelve "i_Inval". }
314 var
315   idInst: TPIC16Inst;
316   tmp: String;
317   found: Boolean;
318 begin
319   found := false;
320   tmp := UpperCase(Op);
321   for idInst := low(TPIC16Inst) to high(TPIC16Inst) do begin
322     if PIC16InstName[idInst] = tmp then begin
323       found := true;
324       break;
325     end;
326   end;
327   if found then begin
328     Result := idInst;
329     syntax := PIC16InstSyntax[idInst];
330   end else  begin
331     Result := i_Inval;
332   end;
333 end;
334 //Campos para procesar instrucciones
GetBanknull335 function TPIC16.GetBank(i : Longint): TPICRAMBank;
336 begin
337   Result.AddrStart := i*PICBANKSIZE;
338   Result.AddrEnd   := (i+1)*PICBANKSIZE-1;
339 end;
GetPagenull340 function TPIC16.GetPage(i: Longint): TPICFlashPage;
341 begin
342   Result.AddrStart := i*PICPAGESIZE;
343   Result.AddrEnd   := (i+1)*PICPAGESIZE-1;
344 end;
TPIC16.GetSTATUSnull345 function TPIC16.GetSTATUS: byte;
346 begin
347   Result := ram[_STATUS].dvalue;
348 end;
TPIC16.GetSTATUS_Znull349 function TPIC16.GetSTATUS_Z: boolean;
350 begin
351   Result := (ram[_STATUS].dvalue and %00000100) <> 0;
352 end;
353 procedure TPIC16.SetSTATUS_Z(AValue: boolean);
354 begin
355   if AVAlue then ram[_STATUS].dvalue := ram[_STATUS].dvalue or  %00000100
356             else ram[_STATUS].dvalue := ram[_STATUS].dvalue and %11111011;
357 end;
GetSTATUS_Cnull358 function TPIC16.GetSTATUS_C: boolean;
359 begin
360   Result := (ram[_STATUS].dvalue and %00000001) <> 0;
361 end;
362 procedure TPIC16.SetSTATUS_C(AValue: boolean);
363 begin
364   if AVAlue then ram[_STATUS].dvalue := ram[_STATUS].dvalue or  %00000001
365             else ram[_STATUS].dvalue := ram[_STATUS].dvalue and %11111110;
366 end;
TPIC16.GetSTATUS_DCnull367 function TPIC16.GetSTATUS_DC: boolean;
368 begin
369   Result := (ram[_STATUS].dvalue and %00000010) <> 0;
370 end;
371 procedure TPIC16.SetSTATUS_DC(AValue: boolean);
372 begin
373   if AVAlue then ram[_STATUS].dvalue := ram[_STATUS].dvalue or  %00000010
374             else ram[_STATUS].dvalue := ram[_STATUS].dvalue and %11111101;
375 end;
GetSTATUS_IRPnull376 function TPIC16.GetSTATUS_IRP: boolean;
377 begin
378   Result := (ram[_STATUS].dvalue and %10000000) <> 0;
379 end;
380 procedure TPIC16.SetSTATUS_IRP(AValue: boolean);
381 begin
382   if AVAlue then ram[_STATUS].dvalue := ram[_STATUS].dvalue or  %10000000
383             else ram[_STATUS].dvalue := ram[_STATUS].dvalue and %01111111;
384 end;
GetINTCONnull385 function TPIC16.GetINTCON: byte;
386 begin
387   Result := ram[$0B].dvalue;
388 end;
TPIC16.GetINTCON_GIEnull389 function TPIC16.GetINTCON_GIE: boolean;
390 begin
391   Result := (ram[$0B].dvalue and %10000000) <> 0;
392 end;
393 procedure TPIC16.SetINTCON_GIE(AValue: boolean);
394 begin
395   if AVAlue then ram[$0B].dvalue := ram[$0B].dvalue or  %10000000
396             else ram[$0B].dvalue := ram[$0B].dvalue and %01111111;
397 end;
398 procedure TPIC16.SetFRAM(value: byte);
399 {Escribe en la RAM; en la dirección global f_, el valor "value"
400 Para determinar el valor real de la dirección, se toma en cuenta los bits de STATUS}
401 var
402   pRAM : TPICRamCellPtr;
403 begin
404   if f_ = 0 then begin
405     //Caso especial de direccionamiento indirecto
406     if STATUS_IRP then begin
407       ram[ram[04].value + $100].value := value;
408     end else begin
409       ram[ram[04].value].value := value;
410     end;
411     exit;
412   end;
413   {Se escribe aplicando la máscara de bits implementados. Se podría usar la máscara en
414   lectura o escritura, pero se prefiere hacerlo en escritura, porque se espera que se
415   hagan menos operaciones de escritura que lectura.}
416   case STATUS and %01100000 of
417   %00000000: pRAM := @ram[f_              ];
418   %00100000: pRAM := @ram[f_+PICBANKSIZE  ];
419   %01000000: pRAM := @ram[f_+PICBANKSIZE*2];
420   %01100000: pRAM := @ram[f_+PICBANKSIZE*3];
421   end;
422   pRAM^.value := value and pRAM^.implemAnd; // or pRAM^.implemOr; No se ha encontrado casos  que requieran implemOr
423   {Se podría optimizar creando una constante en lugar de PICBANKSIZE y evitar así
424   la multiplicación. La constante peude ser glocla, algo así como:
425   cons PIC_BANK_SIZE = 128 y usar luego esta constante para asiganrla a PICBANKSIZE.}
426 end;
GetFRAMnull427 function TPIC16.GetFRAM: byte;
428 {Devuelve el valor de la RAM, de la posición global f_.
429 Para determinar el valor real de la dirección, se toma en cuenta los bits de STATUS}
430 var
431   addr: Byte;
432 begin
433   if f_ = 0 then begin
434     //Caso especial de direccionamiento indirecto
435     if STATUS_IRP then begin
436       Result := ram[ram[04].value + $100].value;
437     end else begin
438       addr := ram[04].value;
439       Result := ram[addr].value and ram[addr].implemAnd;
440     end;
441     exit;
442   end;
443   case STATUS and %01100000 of
444   %00000000: Result := ram[f_               ].value;
445   %00100000: Result := ram[f_+ PICBANKSIZE  ].value;
446   %01000000: Result := ram[f_+ PICBANKSIZE*2].value;
447   %01100000: Result := ram[f_+ PICBANKSIZE*3].value;
448   end;
449 end;
450 procedure TPIC16.Decode(const opCode: word);
451 {Decodifica la instrucción indicada. Actualiza siempre la variable "idIns", y
452 dependiendo de la instrucción, puede actualizar: d_, f_, b_ y k_}
453 var
454   codH : byte;  //6 bits altos de la instrucción
455   codL : byte;  //byte bajo de la instrucción
456 begin
457   codH := (opCode and $3F00) >> 8;  //se debería optimizar
458   codL := opCode and $00FF;
459   case codH of
460   %000111: begin
461     idIns := i_ADDWF;
462     d_ := TPIC16destin(codL and %10000000);
463     f_ := codL and %01111111;
464   end;
465   %000101: begin
466     idIns := i_ANDWF;
467     d_ := TPIC16destin(codL and %10000000);
468     f_ := codL and %01111111;
469   end;
470   %000001: begin
471     if (codL and %10000000) = %10000000 then begin
472       idIns := i_CLRF;
473       f_ := codL and %01111111;
474     end else begin
475       idIns := i_CLRW;
476     end;
477   end;
478   %001001: begin
479     idIns := i_COMF;
480     d_ := TPIC16destin(codL and %10000000);
481     f_ := codL and %01111111;
482   end;
483   %000011: begin
484     idIns := i_DECF;
485     d_ := TPIC16destin(codL and %10000000);
486     f_ := codL and %01111111;
487   end;
488   %001011: begin
489     idIns := i_DECFSZ;
490     d_ := TPIC16destin(codL and %10000000);
491     f_ := codL and %01111111;
492   end;
493   %001010: begin
494     idIns := i_INCF;
495     d_ := TPIC16destin(codL and %10000000);
496     f_ := codL and %01111111;
497   end;
498   %001111: begin
499     idIns := i_INCFSZ;
500     d_ := TPIC16destin(codL and %10000000);
501     f_ := codL and %01111111;
502   end;
503   %000100: begin
504     idIns := i_IORWF;
505     d_ := TPIC16destin(codL and %10000000);
506     f_ := codL and %01111111;
507   end;
508   %001000: begin
509     idIns := i_MOVF;
510     d_ := TPIC16destin(codL and %10000000);
511     f_ := codL and %01111111;
512   end;
513   %000000: begin
514     if (codL and %10000000) = %10000000 then begin
515       idIns := i_MOVWF;
516       f_ := codL and %01111111;
517     end else begin
518       //bit7 a cero, hay varias opciones
519       case codL of
520       %00000000,
521       %00100000,
522       %01000000,
523       %01100000: begin
524         idIns := i_NOP;
525       end;
526       %01100100: begin
527         idIns := i_CLRWDT;
528       end;
529       %00001001: begin
530         idIns := i_RETFIE;
531       end;
532       %00001000: begin
533         idIns := i_RETURN;
534       end;
535       %01100011: begin
536         idIns := i_SLEEP;
537       end;
538       else
539         idIns := i_Inval;
540       end;
541     end;
542   end;
543   %001101: begin
544     idIns := i_RLF;
545     d_ := TPIC16destin(codL and %10000000);
546     f_ := codL and %01111111;
547   end;
548   %001100: begin
549     idIns := i_RRF;
550     d_ := TPIC16destin(codL and %10000000);
551     f_ := codL and %01111111;
552   end;
553   %000010: begin
554     idIns := i_SUBWF;
555     d_ := TPIC16destin(codL and %10000000);
556     f_ := codL and %01111111;
557   end;
558   %001110: begin
559     idIns := i_SWAPF;
560     d_ := TPIC16destin(codL and %10000000);
561     f_ := codL and %01111111;
562   end;
563   %000110: begin
564     idIns := i_XORWF;
565     d_ := TPIC16destin(codL and %10000000);
566     f_ := codL and %01111111;
567   end;
568   %111110,
569   %111111: begin
570     idIns := i_ADDLW;
571     k_ := codL;
572   end;
573   %111001: begin
574     idIns := i_ANDLW;
575     k_ := codL;
576   end;
577   %111000: begin
578     idIns := i_IORLW;
579     k_ := codL;
580   end;
581   %110000,
582   %110001,
583   %110010,
584   %110011: begin
585     idIns := i_MOVLW;
586     k_ := codL;
587   end;
588   %110100,
589   %110101,
590   %110110,
591   %110111: begin
592     idIns := i_RETLW;
593     k_ := codL;
594   end;
595   %111100,
596   %111101: begin
597     idIns := i_SUBLW;
598     k_ := codL;
599   end;
600   %111010: begin
601     idIns := i_XORLW;
602     k_ := codL;
603   end;
604   else
605     if (codH and %110000) = %010000 then begin
606       case codH and %001100 of
607       %0000: begin
608         idIns := i_BCF;
609         b_ := (opCode and %1110000000) >> 7;
610         f_ := codL and %01111111;
611       end;
612       %0100: begin
613         idIns := i_BSF;
614         b_ := (opCode and %1110000000) >> 7;
615         f_ := codL and %01111111;
616       end;
617       %1000: begin
618         idIns := i_BTFSC;
619         b_ := (opCode and %1110000000) >> 7;
620         f_ := codL and %01111111;
621       end;
622       %1100: begin
623         idIns := i_BTFSS;
624         b_ := (opCode and %1110000000) >> 7;
625         f_ := codL and %01111111;
626       end;
627       else
628         idIns := i_Inval;
629       end;
630     end else if (codH and %111000) = %100000 then begin
631       idIns := i_CALL;
632       k_ := opCode and %11111111111;
633     end else if (codH and %111000) = %101000 then begin
634       idIns := i_GOTO;
635       k_ := opCode and %11111111111;
636     end else begin
637       idIns := i_Inval;
638     end;
639   end;
640 end;
Disassemblernull641 function TPIC16.Disassembler(const opCode: word; bankNum: byte = 255;
642                              useVarName: boolean = false): string;
643 {Desensambla la instrucción "opCode". Esta rutina utiliza las variables: d_, f_, b_ y k_
644 "opCode"  -> Código de Operación que se desea decodificar. Se asuem que es de 14 bits.
645 "bankNum" -> Es el banco de trabajo en el que se supone se está decodificando el OpCode.
646              Se usa para determinar la dirección de memoria real a la que se accede
647              (cuando el OpCode alccede a memoria). Si no se conoce el valor, se debe
648              poner en 255.
649 "useVarName" -> Indica que se quiere usar etiquetas para los nombres de las variables
650              (En los Opcode que accedan a memoria). Solo es válido cuando
651              bankNum = 0,1,2,3 y exista un nombre asociado a la variable.
652 }
653 var
654   nemo: String;
655   f: word;
656 begin
657   Decode(opCode);   //Decode instruction. Update: idIns, d_, f_, b_ and k_
658   nemo := lowerCase(trim(PIC16InstName[idIns])) + ' ';
659   case idIns of
660   i_ADDWF,
661   i_ANDWF,
662   i_COMF ,
663   i_DECF ,
664   i_DECFSZ,
665   i_INCF,
666   i_INCFSZ,
667   i_IORWF,
668   i_MOVF,
669   i_RLF,
670   i_RRF,
671   i_SUBWF,
672   i_SWAPF,
673   i_XORWF: begin
674       if bankNum in [0,1,2,3] then begin
675         //Banco conocido
676         f := f_ + PICBANKSIZE*bankNum;  //Dirección real
677       end else begin
678         //Se asume un banco desconocido
679         useVarName := false;  //Desactiva por si acaso
680         bankNum := 0;  //Trabajará en este banco
681         f := f_;       //Dirección asumida
682       end;
683       if useVarName and (ram[f].name<>'') then begin
684         //Required to include address name
685         if d_ = toF then
686           Result := nemo + ram[f].name + ',f'
687         else
688           Result := nemo + ram[f].name + ',w';
689       end else begin
690         //No Required to include address name
691         if d_ = toF then
692           Result := nemo + '0x'+IntToHex(f,3) + ',f'
693         else
694           Result := nemo + '0x'+IntToHex(f,3) + ',w';
695       end;
696      end;
697   i_CLRF,
698   i_MOVWF: begin
699         if bankNum in [0,1,2,3] then begin
700           //Banco conocido
701           f := f_ + PICBANKSIZE*bankNum;  //Dirección real
702         end else begin
703           //Se asume un banco desconocido
704           useVarName := false;  //Desactiva por si acaso
705           bankNum := 0;  //Trabajará en este banco
706           f := f;        //Dirección asumida
707         end;
708         if useVarName and (ram[f].name<>'') then begin
709           Result := nemo + ram[f].name;
710         end else begin
711           Result := nemo + '0x'+IntToHex(f,3);
712         end;
713      end;
714   i_BCF,
715   i_BSF,
716   i_BTFSC,
717   i_BTFSS: begin    //Instrucciones de bit
718       if bankNum in [0,1,2,3] then begin
719         //Banco conocido
720         f := f_ + PICBANKSIZE*bankNum;  //Dirección real
721       end else begin
722         //Se asume un banco desconocido
723         useVarName := false;  //Desactiva por si acaso
724         bankNum := 0;  //Trabajará en este banco
725         f := f;        //Dirección asumida
726       end;
727       if useVarName and (ram[f].bitname[b_]<>'') then begin
728         //Hay nombre de bit
729         Result := nemo + ram[f].bitname[b_];
730       end else if useVarName and (ram[f].name<>'') then begin
731         //Hay nombre de byte
732         Result := nemo + ram[f].name + ', ' + IntToStr(b_);
733       end else begin
734         Result := nemo + '0x'+IntToHex(f,3) + ', ' + IntToStr(b_);
735       end;
736      end;
737   i_ADDLW,
738   i_ANDLW,
739   i_IORLW,
740   i_MOVLW,
741   i_RETLW,
742   i_SUBLW,
743   i_XORLW: begin
744        Result := nemo + '0x'+IntToHex(k_,2);
745      end;
746   i_CALL,
747   i_GOTO: begin   //Faltaría decodificar la dirección
748     Result := nemo + '0x'+IntToHex(k_,3);
749   end;
750   i_CLRW,
751   i_NOP,
752   i_CLRWDT,
753   i_RETFIE,
754   i_RETURN,
755   i_SLEEP: begin
756        Result := nemo ;
757      end;
758   else
759     Result := 'Invalid'
760   end;
761 end;
DisassemblerAtnull762 function TPIC16.DisassemblerAt(addr: word; useVarName: boolean): string;
763 {Disassembler the instruction located at "addr"}
764 var
765   valOp: Word;
766   bnkOp: Byte;
767 begin
768   valOp := flash[addr].value;
769   bnkOp := flash[addr].curBnk;
770   Result := Disassembler(valOp, bnkOp, useVarName);   //desensambla
771 end;
CurInstructionnull772 function TPIC16.CurInstruction: TPIC16Inst;
773 {Resturn the instruction pointed by PC, in this moment.}
774 begin
775   Decode(flash[PC.W].value);   //decodifica instrucción
776   Result := idIns;
777 end;
778 procedure TPIC16.Exec;
779 {Execute the current instruction.}
780 begin
781   Exec(PC.W);
782 end;
783 procedure TPIC16.Exec(aPC: word);
784 {Ejecuta la instrución actual con dirección "pc".
785 Falta implementar las operaciones, cuando acceden al registro INDF, el Watchdog timer,
786 los contadores, las interrupciones}
787 var
788   opc: Word;
789   //fullAdd: word;
790   msk, resNib: byte;
791   resByte, bit7, bit0: byte;
792   resWord: word;
793   resInt : integer;
794 begin
795   //Decode instruction
796   opc := flash[aPC].value;
797   Decode(opc);   //decodifica instrucción
798   case idIns of
799   i_ADDWF: begin
800     resByte := FRAM;
801     resWord := W + resByte;
802     resNib := (W and $0F) + (resByte and $0F);
803     if d_ = toF then begin
804       FRAM := resWord and $FF;
805     end else begin  //toW
806       w := resWord and $FF;
807     end;
808     STATUS_Z := (resWord and $ff) = 0;
809     STATUS_C := (resWord > 255);
810     STATUS_DC := (resNib > 15);
811   end;
812   i_ANDWF: begin
813     resByte := W and FRAM;
814     if d_ = toF then begin
815       FRAM := resByte;
816     end else begin  //toW
817       w := resByte;
818     end;
819     STATUS_Z := resByte = 0;
820   end;
821   i_CLRF: begin
822     FRAM := 0;
823     STATUS_Z := true;
824   end;
825   i_CLRW: begin
826     W := 0;
827     STATUS_Z := true;
828   end;
829   i_COMF : begin
830     resByte := not FRAM;
831     if d_ = toF then begin
832       FRAM := resByte;
833     end else begin  //toW
834       w := resByte;
835     end;
836     STATUS_Z := resByte = 0;
837   end;
838   i_DECF : begin
839     resByte := FRAM;
840     if resByte = 0 then resByte := $FF else dec(resByte);
841     if d_ = toF then begin
842       FRAM := resByte;
843     end else begin  //toW
844       w := resByte;
845     end;
846     STATUS_Z := resByte = 0;
847   end;
848   i_DECFSZ: begin
849     resByte := FRAM;
850     if resByte = 0 then resByte := $FF else dec(resByte);
851     if d_ = toF then begin
852       FRAM := resByte;
853     end else begin  //toW
854       w := resByte;
855     end;
856     STATUS_Z := resByte = 0;
857     if STATUS_Z then begin
858       Inc(PC.W);    //Jump one instrucción
859       Inc(nClck);   //In this case it takes one more cicle
860     end;
861   end;
862   i_INCF: begin
863     resByte := FRAM;
864     if resByte = 255 then resByte := 0 else inc(resByte);
865     if d_ = toF then begin
866       FRAM := resByte;
867     end else begin  //toW
868       w := resByte;
869     end;
870     STATUS_Z := resByte = 0;
871   end;
872   i_INCFSZ: begin
873     resByte := FRAM;
874     if resByte = 255 then resByte := 0 else inc(resByte);
875     if d_ = toF then begin
876       FRAM := resByte;
877     end else begin  //toW
878       w := resByte;
879     end;
880     STATUS_Z := resByte = 0;
881     if STATUS_Z then begin
882       Inc(PC.W);    //Jump one instrucción
883       Inc(nClck);   //In this case it takes one more cicle
884     end;
885   end;
886   i_IORWF: begin
887     resByte := W or FRAM;
888     if d_ = toF then begin
889       FRAM := resByte;
890     end else begin  //toW
891       w := resByte;
892     end;
893     STATUS_Z := resByte = 0;
894   end;
895   i_MOVF: begin
896     resByte := FRAM;
897     if d_ = toF then begin
898       //no mueve, solo verifica
899       STATUS_Z := (resByte = 0);
900     end else begin  //toW
901       w := resByte;
902       STATUS_Z := (resByte = 0);
903     end;
904   end;
905   i_MOVWF: begin
906     FRAM := W;   //escribe a donde esté mapeado, (si está mapeado)
907     if f_ = $02 then begin //Es el PCL
908       PC.H := PCLATH;  //Cuando se escribe en PCL, se carga PCH con PCLATH
909     end;
910   end;
911   i_NOP: begin
912   end;
913   i_RLF: begin
914     resByte := FRAM;
915     bit7 := resByte and $80; //guarda bit 7
916     resByte := (resByte << 1) and $ff;  //desplaza
917     //pone C en bit bajo
918     if STATUS_C then begin  //C era 1
919       resByte := resByte or $01;  //pone a 1 el bit 0
920     end else begin          //C era 0
921       //no es necesario agregarlo, porque por defecto se agrega 0
922     end;
923     //Actualiza C
924     if bit7 = 0 then STATUS_C := false
925                 else STATUS_C := true;
926     if d_ = toF then begin
927       FRAM := resByte;
928     end else begin  //toW
929       w := resByte;
930     end;
931   end;
932   i_RRF: begin
933     resByte := FRAM;
934     bit0 := resByte and $01; //guarda bit 0
935     resByte := resByte >> 1;  //desplaza
936     //pone C en bit alto
937     if STATUS_C then begin  //C era 1
938       resByte := resByte or $80;  //pone a 1 el bit 0
939     end else begin          //C era 0
940       //no es necesario agregarlo, porque por defecto se agrega 0
941     end;
942     //Actualiza C
943     if bit0 = 0 then STATUS_C := false
944                 else STATUS_C := true;
945     if d_ = toF then begin
946       FRAM := resByte;
947     end else begin  //toW
948       w := resByte;
949     end;
950   end;
951   i_SUBWF: begin
952     resByte := FRAM;
953     resInt := resByte - W;
954     if d_ = toF then begin
955       FRAM :=  resInt and $FF;
956     end else begin  //toW
957       w := resInt and $FF;
958     end;
959     STATUS_Z := (resInt = 0);
960     if resInt < 0 then STATUS_C := false   //negativo
961     else STATUS_C := true;
962     resInt := (resByte and $0F) - (W and $0F);
963     if resInt < 0 then STATUS_DC := false   //negativo
964     else STATUS_DC := true;
965   end;
966   i_SWAPF: begin
967     resByte := FRAM;
968     FRAM := (resByte >> 4) or (resByte << 4);
969   end;
970   i_XORWF: begin
971     resByte := W xor FRAM;
972     if d_ = toF then begin
973       FRAM := resByte;
974     end else begin  //toW
975       w := resByte;
976     end;
977     STATUS_Z := resByte = 0;
978   end;
979   //BIT-ORIENTED FILE REGISTER OPERATIONS
980   i_BCF: begin
981     msk := $1 << b_;
982     msk := not msk;
983     FRAM := FRAM and msk;
984   end;
985   i_BSF: begin
986     msk := $1 << b_;
987     FRAM := FRAM or msk;// b_
988   end;
989   i_BTFSC: begin
990     msk := $1 << b_;
991     if (FRAM and msk) = 0 then begin
992       Inc(PC.W);    //Jump one instrucción
993       Inc(nClck);   //In this case it takes one more cicle
994     end;
995   end;
996   i_BTFSS: begin
997     msk := $1 << b_;
998     if (FRAM and msk) <> 0 then begin
999       Inc(PC.W);    //Jump one instrucción
1000       Inc(nClck);   //In this case it takes one more cicle
1001     end;
1002   end;
1003   //LITERAL AND CONTROL OPERATIONS
1004   i_ADDLW: begin
1005     resWord := W + k_;
1006     resNib := (W and $0F) + (k_ and $0F);
1007     w := resWord and $FF;
1008     STATUS_Z := (resWord and $ff) = 0;
1009     STATUS_C := (resWord > 255);
1010     STATUS_DC := (resNib > 15);
1011   end;
1012   i_ANDLW: begin
1013     resByte := W and K_;
1014     w := resByte;
1015     STATUS_Z := resByte = 0;
1016   end;
1017   i_CALL: begin
1018     //Guarda dirección en Pila
1019     STACK[STKPTR] := PC.W;
1020     if STKPTR = 7 then begin
1021       //Desborde de pila
1022       STKPTR := 0;
1023       if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on CALL OpCode at $' + IntToHex(aPC,4));
1024     end else begin
1025       STKPTR := STKPTR +1;
1026     end;
1027     PC.W := k_;  //Takes the 11 bits from k
1028     PC.H := PC.H or (PCLATH and %00011000);  //And complete with bits 3 and 4 of PCLATH
1029     Inc(nClck,2);   //This instruction takes two cicles
1030     exit;
1031   end;
1032   i_CLRWDT: begin
1033   end;
1034   i_GOTO: begin
1035     PC.W := k_;  //Takes the 11 bits from k
1036     PC.H := PC.H or (PCLATH and %00011000);  //And complete with bits 3 and 4 of PCLATH
1037     Inc(nClck,2);   //This instruction takes two cicles
1038     exit;
1039   end;
1040   i_IORLW: begin
1041     resByte := W or k_;
1042     w := resByte;
1043     STATUS_Z := resByte = 0;
1044   end;
1045   i_MOVLW: begin
1046       W := k_;
1047   end;
1048   i_RETFIE: begin
1049     //Saca dirección en Pila
1050     if STKPTR = 0 then begin
1051       //Desborde de pila
1052       STKPTR := 7;
1053       if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on RETFIE OpCode at $' + IntToHex(aPC,4));
1054     end else begin
1055       STKPTR := STKPTR - 1;
1056     end;
1057     PC.W := STACK[STKPTR];  //Should be 13 bits
1058     Inc(nClck);   //Esta instrucción toma un ciclo más
1059     //Activa GIE
1060     INTCON_GIE := true;
1061   end;
1062   i_RETLW: begin
1063     //Saca dirección en Pila
1064     if STKPTR = 0 then begin
1065       //Desborde de pila
1066       STKPTR := 7;
1067       if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on RETLW OpCode at $' + IntToHex(aPC,4));
1068     end else begin
1069       STKPTR := STKPTR - 1;
1070     end;
1071     PC.W := STACK[STKPTR];  //Should be 13 bits
1072     Inc(nClck);   //Esta instrucción toma un ciclo más
1073     //Fija valor en W
1074     W := k_;
1075   end;
1076   i_RETURN: begin
1077     //Saca dirección en Pila
1078     if STKPTR = 0 then begin
1079       //Desborde de pila
1080       STKPTR := 7;
1081       if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on RETURN OpCode at $' + IntToHex(aPC,4));
1082     end else begin
1083       STKPTR := STKPTR - 1;
1084     end;
1085     PC.W := STACK[STKPTR];  //Should be 13 bits
1086     Inc(nClck);   //Esta instrucción toma un ciclo más
1087   end;
1088   i_SLEEP: begin
1089   end;
1090   i_SUBLW: begin
1091     resInt := k_ - W;
1092     w := resInt and $FF;
1093     STATUS_Z := (resInt = 0);
1094     if resInt < 0 then STATUS_C := false   //negativo
1095     else STATUS_C := true;
1096     resInt := (k_ and $0F) - (W and $0F);
1097     if resInt < 0 then STATUS_DC := false   //negativo
1098     else STATUS_DC := true;
1099   end;
1100   i_XORLW: begin
1101     resByte := W xor k_;
1102     w := resByte;
1103     STATUS_Z := resByte = 0;
1104   end;
1105   i_Inval: begin
1106     MsjError := 'Invalid Opcode';
1107   end;
1108   end;
1109   //Incrementa contador
1110   Inc(PC.W);
1111   Inc(nClck);
1112 end;
1113 procedure TPIC16.ExecTo(endAdd: word);
1114 {Ejecuta las instrucciones secuencialmente, desde la instrucción actual, hasta que el
1115 contador del programa, sea igual a la dirección "endAdd".}
1116 begin
1117   //Hace una primera ejecución, sin verificar Breakpoints
1118   Exec(PC.W);
1119   //Ejecuta cíclicamnente
1120   while PC.W <> endAdd do begin
1121     if flash[PC.W].breakPnt then begin
1122       //Encontró un BreakPoint, sale sin ejecutar esa instrucción
1123       if OnExecutionMsg<>nil then OnExecutionMsg('Stopped for breakpoint.');
1124       exit;
1125     end;
1126     //Ejecuta
1127     Exec(PC.W);
1128     //Debe haber una forma de salir si es un lazo infinito
1129     //if (nClck and $800000) = $800000 then begin
1130     //end;
1131   end;
1132 end;
1133 procedure TPIC16.ExecStep;
1134 begin
1135   if CurInstruction = i_CALL then begin
1136     ExecTo(PC.W+1);  //Ejecuta hasta la sgte. instrucción, salta el i_CALL
1137   end else begin
1138     Exec;
1139   end;
1140 end;
1141 procedure TPIC16.ExecNCycles(nCyc: integer; out stopped: boolean);
1142 {Ejecuta el número de ciclos indicados, o hasta que se produzca alguna condición
1143 externa, que puede ser:
1144 * Se encuentre un Punto de Interrupción.
1145 * Se detecta la señal, de detenerse.
1146 * Se genere algún error en la ejecución.
1147 * Se ejecuta la instrucción i_SLEEP.
1148 la bandera "stopped", indica que se ha detendio la ejecución sin completar la cantidad
1149 de instrucciones requeridas.
1150 Normalmente Se ejecutará el número de ciclos indicados, pero en algunos casos se
1151 ejecutará un ciclo más, debido a que algunas instrucciones toman dos ciclos.}
1152 var
1153   clkEnd: Int64;
1154   _pc: word;
1155 begin
1156   clkEnd := nClck + nCyc;   //Valor final del contador
1157   while nClck < clkEnd do begin
1158     _pc := PC.W;
1159     if flash[_pc].breakPnt then begin
1160       //Encontró un BreakPoint, sale sin ejecutar esa instrucción
1161       if OnExecutionMsg<>nil then OnExecutionMsg('Stopped for breakpoint.');
1162       stopped := true;
1163       exit;
1164     end;
1165     if not flash[_pc].used then begin
1166       //Encontró un BreakPoint, sale sin ejecutar esa instrucción
1167       if OnExecutionMsg<>nil then OnExecutionMsg('Stopped for executing unused code.');
1168       stopped := true;
1169       exit;
1170     end;
1171     if CommStop then begin
1172       //Se detectó el comando STOP
1173       if OnExecutionMsg<>nil then OnExecutionMsg('Stopped for STOP command.');
1174       stopped := true;
1175       exit;
1176     end;
1177     //Ejecuta
1178     Exec(_pc);
1179     if idIns = i_SLEEP then begin
1180       //Encontró un BreakPoint, sale sin ejecutar esa instrucción
1181       if OnExecutionMsg<>nil then OnExecutionMsg('Stopped for SLEEP Opcode.');
1182       stopped := true;
1183       exit;
1184     end;
1185   end;
1186   stopped := false;
1187 end;
1188 procedure TPIC16.Reset;
1189 //Reinicia el dipsoitivo
1190 var
1191   i: Integer;
1192 begin
1193   PC.W   := 0;
1194   PCLATH := 0;
1195   W      := 0;
1196   STKPTR := 0;   //Posición inicial del puntero de pila
1197   nClck  := 0;   //Inicia contador de ciclos
1198   CommStop := false;  //Limpia bandera
1199   //Limpia solamente el valor inicial, no toca los otros campos
1200   for i:=0 to high(ram) do begin
1201     ram[i].dvalue := $00 or
1202            ram[i].implemOr;  //To set unimplemented bits fixed to "1".
1203   end;
1204   ram[_STATUS].dvalue := %00011000;  //STATUS
1205   ram[$85].dvalue := $FF and ram[$85].implemAnd or ram[$85].implemOr;  //TRISA
1206   ram[$86].dvalue := $FF and ram[$86].implemAnd or ram[$86].implemOr;  //TRISB
1207   ram[$87].dvalue := $FF and ram[$87].implemAnd or ram[$87].implemOr;  //TRISC
1208   //No todos los PIC tienen PORTD y PORTE. Usamos este método indirecto para averiguarlo
1209   if ram[$0C].state = cs_impleSFR then begin
1210     ram[$88].dvalue := $FF and ram[$88].implemAnd or ram[$88].implemOr;  //TRISD
1211     ram[$89].dvalue := $FF and ram[$89].implemAnd or ram[$89].implemOr;  //TRISE
1212   end;
1213 end;
ReadPCnull1214 function TPIC16.ReadPC: dword;
1215 begin
1216   Result := PC.W;
1217 end;
1218 procedure TPIC16.WritePC(AValue: dword);
1219 begin
1220   PC.W := AValue;
1221 end;
1222 //Funciones para la memoria RAM
GetFreeBitnull1223 function TPIC16.GetFreeBit(out addr: word; out bit: byte; shared: boolean): boolean;
1224 {Devuelve una dirección libre de la memoria RAM (y el banco).
1225 "Shared" indica que se marcará el bit como de tipo "Compartido", y se usa para el
1226 caso en que se quiera comaprtir la misma posición para diversos variables.
1227 Si encuentra espacio, devuelve TRUE.}
1228 var
1229   maxRam: word;
1230   i: Integer;
1231 begin
1232   Result := false;   //valor inicial
1233   maxRam := NumBanks * PICBANKSIZE;  //posición máxima
1234   //Realmente debería explorar solo hasta la dirección implementada, por eficiencia
1235   for i:=0 to maxRam-1 do begin
1236     if (ram[i].state = cs_impleGPR) and (ram[i].used <> 255) then begin
1237       //Esta dirección tiene al menos un bit libre
1238       addr := i;  //devuelve dirección
1239       //busca el bit libre
1240       if          (ram[i].used and %00000001) = 0 then begin
1241         bit:=0;
1242       end else if (ram[i].used and %00000010) = 0 then begin
1243         bit:=1
1244       end else if (ram[i].used and %00000100) = 0 then begin
1245         bit:=2
1246       end else if (ram[i].used and %00001000) = 0 then begin
1247         bit:=3
1248       end else if (ram[i].used and %00010000) = 0 then begin
1249         bit:=4
1250       end else if (ram[i].used and %00100000) = 0 then begin
1251         bit:=5
1252       end else if (ram[i].used and %01000000) = 0 then begin
1253         bit:=6
1254       end else if (ram[i].used and %10000000) = 0 then begin
1255         bit:=7
1256       end;
1257       ram[i].used := ram[i].used or (byte(1)<<bit); //marca bit usado
1258       if shared then begin
1259         ram[i].shared:= ram[i].shared or (byte(1)<<bit); //marca bit compartido
1260       end;
1261       //Notar que la posición de memoria puede estar mapeada a otro banco.
1262       Result := true;  //indica que encontró espacio
1263       exit;
1264     end;
1265   end;
1266 end;
GetFreeBytenull1267 function TPIC16.GetFreeByte(out addr: word; shared: boolean): boolean;
1268 {Devuelve una dirección libre de la memoria flash.
1269 "Shared" indica que se marcará el bit como de tipo "Compartido", y se usa para el
1270 caso en que se quiera comaprtir la misma posición para diversos variables.
1271 Si encuentra espacio, devuelve TRUE.}
1272 var
1273   i: Integer;
1274   maxRam: word;
1275 begin
1276   Result := false;   //valor inicial
1277   maxRam := NumBanks * PICBANKSIZE;  //posición máxima
1278   //Realmente debería explorar solo hasta la dirección implementada, por eficiencia
1279   for i:=0 to maxRam-1 do begin
1280     if (ram[i].state = cs_impleGPR) and (ram[i].used = 0) then begin
1281       //Esta dirección está libre
1282       ram[i].used:=255;   //marca como usado
1283       if shared then begin
1284         ram[i].shared := 255;  //Marca como compartido
1285       end;
1286       addr := i;
1287       //Notar que la posición de memoria puede estar mapeada a otro banco.
1288       Result := true;  //indica que encontró espacio
1289       exit;
1290     end;
1291   end;
1292 end;
GetFreeBytesnull1293 function TPIC16.GetFreeBytes(const size: integer; var addr: word): boolean;
1294 {Devuelve una dirección libre de la memoria flash (y el banco) para ubicar un bloque
1295  del tamaño indicado. Si encuentra espacio, devuelve TRUE.
1296  El tamaño se da en bytes, pero si el valor es negativo, se entiende que es en bits.}
1297 var
1298   i: word;
1299   maxRam: Word;
1300 begin
1301   Result := false;  //valor por defecto
1302   if size=0 then exit;
1303   maxRam := word(NumBanks * PICBANKSIZE) - 1;
1304   for i:=0 to maxRam do begin  //verifica 1 a 1, por seguridad
1305     if HaveConsecGPR(i, size, maxRam) then begin
1306       //encontró del tamaño buscado
1307       UseConsecGPR(i, size);  //marca como usado
1308       addr := i;
1309       Result := true;  //indica que encontró espacio
1310       exit;
1311     end;
1312   end;
1313 end;
TPIC16.TotalMemRAMnull1314 function TPIC16.TotalMemRAM: word;
1315 {Devuelve el total de memoria RAM disponible}
1316 var
1317   i: Integer;
1318 begin
1319   Result := 0;
1320   for i := 0 to word(NumBanks * PICBANKSIZE) - 1 do begin
1321     if i > high(ram) then exit;  //Protection
1322     if ram[i].AvailGPR then begin
1323       Result := Result + 1;
1324     end;
1325   end;
1326 end;
TPIC16.UsedMemRAMnull1327 function TPIC16.UsedMemRAM: word;
1328 {Devuelve el total de memoria RAM usada}
1329 var
1330   i: Integer;
1331 begin
1332   Result := 0;
1333   for i := 0 to word(NumBanks * PICBANKSIZE) - 1 do begin
1334     if i > high(ram) then exit;  //Protection
1335     if ram[i].AvailGPR and (ram[i].used <> 0) then begin
1336       //Notar que "AvailGPR" asegura que no se consideran registros maepados
1337       Result := Result + 1;
1338     end;
1339   end;
1340 end;
1341 procedure TPIC16.ExploreUsed(rutExplorRAM: TPICRutExplorRAM);
1342 {Genera un reporte de uso de RAM}
1343 var
1344   i: Integer;
1345 begin
1346   for i := 0 to word(NumBanks * PICBANKSIZE) - 1 do begin
1347     if i > high(ram) then exit;  //Protection
1348     if ram[i].AvailGPR and (ram[i].used <> 0) then begin
1349       rutExplorRAM(i, 0, @ram[i]);
1350     end;
1351   end;
1352 end;
TPIC16.ValidRAMaddrnull1353 function TPIC16.ValidRAMaddr(addr: word): boolean;
1354 {Indica si la dirección indicada es válida dentro del hardware del PIC}
1355 begin
1356   if addr > PICBANKSIZE*NumBanks then exit(false);   //excede límite
1357   exit(true);
1358 end;
BankToAbsRAMnull1359 function TPIC16.BankToAbsRAM(const offset, bank: byte): word;
1360 {Convierte una dirección y banco a una dirección absoluta}
1361 begin
1362   Result := bank * PICBANKSIZE + offset;
1363 end;
1364 procedure TPIC16.AbsToBankRAM(const AbsAddr: word; var offset, bank: byte);
1365 {Convierte dirección absoluta a dirección en bancos}
1366 begin
1367    offset := AbsAddr and %01111111;
1368    bank :=  AbsAddr >> 7;
1369 end;
1370 procedure TPIC16.GenHex(hexFile: string; ConfigWord: integer = -1);
1371 {Genera el archivo *.hex, a partir de los datos almacenados en la memoria
1372 FLASH.
1373 Actualiza los campos, minUsed y maxUsed.}
1374 var
1375   cfg, tmp: String;
1376   iHex: word;  //Índice para explorar
1377   dat: String; //Cadena de dígitos hexadecimales
1378   addr: word;  //Dirección de inicio
1379 const
1380   MAX_INS_HEX = 8;  //Número máximo de instrucciones que devuelve por pasada
1381 
ExtractHexnull1382   function ExtractHex(out Addre: word): string;
1383   {Devuelve una cadena (de longitud que varía desde 0, hasta MAX_INS_HEX*4 caracteres)
1384   con valores en hexadecimal de isntrucciones, consecutivas usadas, en le memoria FLASH.
1385   La lectura se hace a partir de iHex, y los caracteres en hexadecimal se escriben en 4
1386   dígitos, en la misma forma que se usan para los archivos *.HEX.
1387   En "Addr" devuelve la dirección absoluta de inicio desde donde lee. Con cada llamada,
1388   devuelve los bloques consecutivos de datos. Si no hay más datos devuelve cadena vacía.}
1389   var p1, p2: word;
1390       cont, p: word;
1391       tmp: String;
1392   begin
1393     Result := '';
1394     //Busca inicio de instrucciones usadas, desde la posición iHex
1395     while (iHex<PICMAXFLASH) and not flash[iHex].used  do begin
1396       inc(iHex);
1397     end;
1398     if iHex>=PICMAXFLASH then begin
1399       //Llegó al final
1400       exit;  //sale con cadena nula
1401     end;
1402     //Ya encontró el inicio ahora busca celdas consecutivas
1403     p1 := iHex;
1404     Addre := p1;
1405     cont := 2;  //inicia contador
1406     inc(iHex);  //pasa al siguiente
1407     while (iHex<PICMAXFLASH) and (cont<MAX_INS_HEX) and flash[iHex].used do begin
1408       inc(iHex);
1409       inc(cont);
1410     end;
1411     if iHex>=PICMAXFLASH then begin
1412       //Salió porque Llegó al final
1413       p2 := PICMAXFLASH-1;
1414     end else if cont>=MAX_INS_HEX then begin
1415       //Salió porque llegó al máximo de celdas
1416       if flash[iHex].used then begin
1417         //La ultima celda estaba ocupada
1418         p2 := iHex;
1419         inc(iHex);   //deja listo para la siguiente exploración
1420       end else begin
1421         //La ultima celda estaba ocupada
1422         p2 := iHex-1;
1423         //iHex, queda apuntando a la siguiente celda
1424       end;
1425     end else begin
1426       //Salió porque encontró celda sin usar
1427       p2 := iHex-1;
1428       //iHex, queda apuntando a la siguiente celda
1429     end;
1430     //Ya tiene las dos posiciones
1431     tmp := '';
1432     for p:=p1 to p2 do begin
1433       if p1<minUsed then minUsed := p1;   //Actualiza
1434       if p2>maxUsed then maxUsed := p2;   //Actualiza
1435       tmp := IntToHex(flash[p].value, 4);
1436       Result +=copy(tmp,3,2) + copy(tmp,1,2);  //se graba con los bytes invertidos
1437     end;
1438   end;
1439 
1440 begin
1441   hexLines.Clear;      //Se usará la lista hexLines
1442   GenHexExAdd($0000);
1443   //Prepara extracción de datos
1444   minUsed := PICMAXFLASH;
1445   maxUsed := 0;
1446   iHex := 0;
1447   //Inicia la extracción de código
1448   dat := ExtractHex(addr);
1449   while dat <>'' do begin
1450      GenHexData(addr, dat);
1451      dat := ExtractHex(addr);
1452   end;
1453   //Bits de configuración
1454   tmp := '';
1455   if ConfigWord<>-1 then begin
1456     //Se pide generar bits de configuración
1457     {Los bits de configuración para la serie 16F, se almacenan en:
1458 Config: 0x2007 (0x400E in the HEX file)
1459 EEPROM: 0x2100 (0x4200 in the HEX file) }
1460     cfg := IntToHex(ConfigWord and $FFFF, 4);
1461     tmp +=copy(cfg,3,2) + copy(cfg,1,2);  //se graba con los bytes invertidos
1462     GenHexData($2007, tmp);
1463   end;
1464   GenHexEOF;                    //Fin de archivo
1465   GenHexComm(self.Model);       //Comentario
1466   hexLines.SaveToFile(hexFile); //Genera archivo
1467 end;
1468 procedure TPIC16.DumpCode(lOut: TStrings; incAdrr, incCom, incVarNam: boolean);
1469 {Desensambla las instrucciones grabadas en el PIC.
1470  Se debe llamar despues de llamar a GenHex(), para que se actualicen las variables}
1471 var
1472   i: Word;
1473   lblLin, comLat, comLin, lin: String;
1474 begin
1475   //Se supone que minUsed y maxUsed, ya deben haber sido actualizados.
1476   for i := minUsed to maxUsed do begin
1477     //Lee comentarios y etiqueta
1478     lblLin := flash[i].topLabel;
1479     comLat := flash[i].sideComment;
1480     comLin := flash[i].topComment;
1481     //Escribe etiqueta al inicio de línea
1482     if lblLin<>'' then lOut.Add(lblLin+':');
1483     //Escribe comentario al inicio de línea
1484     if incCom and (comLin<>'') then  begin
1485       lOut.Add(comLin);
1486     end;
1487     //Decodifica instrucción
1488     lin := DisassemblerAt(i, incVarNam);  //Instrucción
1489     //Verificas si incluye dirección física
1490     if incAdrr then  begin
1491       lin := '0x'+IntToHex(i,3) + ' ' + lin;
1492     end;
1493     //Verifica si incluye comentario lateral
1494     if incCom then begin
1495       lin := lin  + ' ' + comLat;
1496     end;
1497     lOut.Add('    ' + lin);
1498   end;
1499 end;
1500 constructor TPIC16.Create;
1501 begin
1502   inherited Create;
1503   PICBANKSIZE := 128;     //RAM bank size
1504   PICMAXRAM   := PICBANKSIZE * 4; //Máx RAM memory (4 banks)
1505   PICPAGESIZE := 2048;
1506   PICMAXFLASH := PICPAGESIZE * 4; //Máx Flash memeory (4 pages)
1507   SetLength(ram, PICMAXRAM);
1508   SetLength(flash, PICMAXFLASH);
1509   //Default hardware settings
1510   NumBanks:=2;     //Número de bancos de RAM. Por defecto se asume 2
1511   NumPages:=1;     //Número de páginas de memoria Flash. Por defecto 1
1512   MaxFlash := PICPAGESIZE;  //En algunos casos, puede ser menor al tamaño de una página
1513   //inicia una configuración común
1514   ClearMemRAM;
1515   SetStatRAM($020, $04F, cs_impleGPR);
1516 
1517   //estado inicial
1518   iFlash := 0;   //posición de inicio
1519   ClearMemFlash;
1520 end;
1521 destructor TPIC16.Destroy;
1522 begin
1523   inherited Destroy;
1524 end;
1525 procedure InitTables;
1526 begin
1527   //Inicializa Mnemónico de instrucciones
1528   PIC16InstName[i_ADDWF ] := 'ADDWF';
1529   PIC16InstName[i_ANDWF ] := 'ANDWF';
1530   PIC16InstName[i_CLRF  ] := 'CLRF';
1531   PIC16InstName[i_CLRW  ] := 'CLRW';
1532   PIC16InstName[i_COMF  ] := 'COMF';
1533   PIC16InstName[i_DECF  ] := 'DECF';
1534   PIC16InstName[i_DECFSZ] := 'DECFSZ';
1535   PIC16InstName[i_INCF  ] := 'INCF';
1536   PIC16InstName[i_INCFSZ] := 'INCFSZ';
1537   PIC16InstName[i_IORWF ] := 'IORWF';
1538   PIC16InstName[i_MOVF  ] := 'MOVF';
1539   PIC16InstName[i_MOVWF ] := 'MOVWF';
1540   PIC16InstName[i_NOP   ] := 'NOP';
1541   PIC16InstName[i_RLF   ] := 'RLF';
1542   PIC16InstName[i_RRF   ] := 'RRF';
1543   PIC16InstName[i_SUBWF ] := 'SUBWF';
1544   PIC16InstName[i_SWAPF ] := 'SWAPF';
1545   PIC16InstName[i_XORWF ] := 'XORWF';
1546   PIC16InstName[i_BCF   ] := 'BCF';
1547   PIC16InstName[i_BSF   ] := 'BSF';
1548   PIC16InstName[i_BTFSC ] := 'BTFSC';
1549   PIC16InstName[i_BTFSS ] := 'BTFSS';
1550   PIC16InstName[i_ADDLW ] := 'ADDLW';
1551   PIC16InstName[i_ANDLW ] := 'ANDLW';
1552   PIC16InstName[i_CALL  ] := 'CALL';
1553   PIC16InstName[i_CLRWDT] := 'CLRWDT';
1554   PIC16InstName[i_GOTO ] := 'GOTO';
1555   PIC16InstName[i_IORLW ] := 'IORLW';
1556   PIC16InstName[i_MOVLW ] := 'MOVLW';
1557   PIC16InstName[i_RETFIE] := 'RETFIE';
1558   PIC16InstName[i_RETLW ] := 'RETLW';
1559   PIC16InstName[i_RETURN] := 'RETURN';
1560   PIC16InstName[i_SLEEP ] := 'SLEEP';
1561   PIC16InstName[i_SUBLW ] := 'SUBLW';
1562   PIC16InstName[i_XORLW ] := 'XORLW';
1563   PIC16InstName[i_Inval] := '<Inval>';
1564 
1565   //Inicializa Sintaxis de las instrucciones
1566   {Los valorees para la sintaxis significan:
1567   f->dirección de un registro en RAM (0..127)
1568   d->destino (W o F)
1569   b->número de bit (0..7)
1570   a->dirección destino (0..$7FF)
1571   k->literal byte (0..255)
1572   }
1573   PIC16InstSyntax[i_ADDWF ] := 'fd';
1574   PIC16InstSyntax[i_ANDWF ] := 'fd';
1575   PIC16InstSyntax[i_CLRF  ] := 'f';
1576   PIC16InstSyntax[i_CLRW  ] := '';
1577   PIC16InstSyntax[i_COMF  ] := 'fd';
1578   PIC16InstSyntax[i_DECF  ] := 'fd';
1579   PIC16InstSyntax[i_DECFSZ] := 'fd';
1580   PIC16InstSyntax[i_INCF  ] := 'fd';
1581   PIC16InstSyntax[i_INCFSZ] := 'fd';
1582   PIC16InstSyntax[i_IORWF ] := 'fd';
1583   PIC16InstSyntax[i_MOVF  ] := 'fd';
1584   PIC16InstSyntax[i_MOVWF ] := 'f';
1585   PIC16InstSyntax[i_NOP   ] := '';
1586   PIC16InstSyntax[i_RLF   ] := 'fd';
1587   PIC16InstSyntax[i_RRF   ] := 'fd';
1588   PIC16InstSyntax[i_SUBWF ] := 'fd';
1589   PIC16InstSyntax[i_SWAPF ] := 'fd';
1590   PIC16InstSyntax[i_XORWF ] := 'fd';
1591   PIC16InstSyntax[i_BCF   ] := 'fb';
1592   PIC16InstSyntax[i_BSF   ] := 'fb';
1593   PIC16InstSyntax[i_BTFSC ] := 'fb';
1594   PIC16InstSyntax[i_BTFSS ] := 'fb';
1595   PIC16InstSyntax[i_ADDLW ] := 'k';
1596   PIC16InstSyntax[i_ANDLW ] := 'k';
1597   PIC16InstSyntax[i_CALL  ] := 'a';
1598   PIC16InstSyntax[i_CLRWDT] := '';
1599   PIC16InstSyntax[i_GOTO ] := 'a';
1600   PIC16InstSyntax[i_IORLW ] := 'k';
1601   PIC16InstSyntax[i_MOVLW ] := 'k';
1602   PIC16InstSyntax[i_RETFIE] := '';
1603   PIC16InstSyntax[i_RETLW ] := 'k';
1604   PIC16InstSyntax[i_RETURN] := '';
1605   PIC16InstSyntax[i_SLEEP ] := '';
1606   PIC16InstSyntax[i_SUBLW ] := 'k';
1607   PIC16InstSyntax[i_XORLW ] := 'k';
1608   PIC16InstSyntax[i_Inval] := '<???>';
1609 end;
1610 initialization
1611   InitTables;
1612 end.
1613 
1614