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