diff --git a/p6502utils.pas b/p6502utils.pas deleted file mode 100644 index 99d2a9d..0000000 --- a/p6502utils.pas +++ /dev/null @@ -1,1550 +0,0 @@ -{ -Description -=========== -Utilities for the 6502 CPU. The types here defined are intended to be used for: -* Assembling 6502 instructions. -* Disassembling 6502 instructions. -* Simulating the 6502 execution. -To simulate the CPU, it's assumed there are 64KB of RAM in a virtual system. -The main class TP6502 models a CPU6502 object including access to 64KB RAM. -The aim of this unit is to be used as base for assemblers, compilers and simulators. - - Created by Tito Hinostroza 19/05/2018 -} - -unit P6502utils; -{$mode objfpc}{$H+} -interface -uses - Classes, SysUtils, LCLProc, PicCore; -type //Instructions set - TP6502Inst = ( - i_ADC, //add with carry - i_AND, //and (with accumulator) - i_ASL, //arithmetic shift left - i_BCC, //branch on carry clear - i_BCS, //branch on carry set - i_BEQ, //branch on equal (zero set) - i_BIT, //bit test - i_BMI, //branch on minus (negative set) - i_BNE, //branch on not equal (zero clear) - i_BPL, //branch on plus (negative clear) - i_BRK, //break / interrupt - i_BVC, //branch on overflow clear - i_BVS, //branch on overflow set - i_CLC, //clear carry - i_CLD, //clear decimal - i_CLI, //clear interrupt disable - i_CLV, //clear overflow - i_CMP, //compare (with accumulator) - i_CPX, //compare with X - i_CPY, //compare with Y - i_DEC, //decrement - i_DEX, //decrement X - i_DEY, //decrement Y - i_EOR, //exclusive or (with accumulator) - i_INC, //increment - i_INX, //increment X - i_INY, //increment Y - i_JMP, //jump - i_JSR, //jump subroutine - i_LDA, //load accumulator - i_LDX, //load X - i_LDY, //load Y - i_LSR, //logical shift right - i_NOP, //no operation - i_ORA, //or with accumulator - i_PHA, //push accumulator - i_PHP, //push processor status (SR) - i_PLA, //pull accumulator - i_PLP, //pull processor status (SR) - i_ROL, //rotate left - i_ROR, //rotate right - i_RTI, //return from interrupt - i_RTS, //return from subroutine - i_SBC, //subtract with carry - i_SEC, //set carry - i_SED, //set decimal - i_SEI, //set interrupt disable - i_STA, //store accumulator - i_STX, //store X - i_STY, //store Y - i_TAX, //transfer accumulator to X - i_TAY, //transfer accumulator to Y - i_TSX, //transfer stack pointer to X - i_TXA, //transfer X to accumulator - i_TXS, //transfer X to stack pointer - i_TYA, //transfer Y to accumulator - //INVALID INSTRUCTION - i_Inval - ); - //Addressing Modes - {Implicit Mode and Acumulator Mode are not considered here. We consider - Only Modes with parameters.} - TP6502AddMode = ( - aImplied_, //Implied : BRK - aAcumulat, //Acumulator : ASL - aImmediat, //Immediate : ORA #$B2 - aAbsolute, //Absolute : JMP $4032 - aZeroPage, //Zero page : LDA: $35 - aRelative, //Relative : BNE LABEL - aIndirect, //Indirect : JMP ($1000) - aAbsolutX, //Absolute Indexed by X : STA $1000, X - aAbsolutY, //Absolute Indexed by Y : STA $1000, Y - aZeroPagX, //Zero page Indexed by X : LDA $10, X - aZeroPagY, //Zero page Indexed by Y : LDA $10, Y - aIdxIndir, //Indexed Indirect: LDA ($40,X) Only for X - aIndirIdx //Indirect Indexed: LDA ($40),Y Only for Y - ); - TP6502AddModes = set of TP6502AddMode; - //Instruction Information for each Address Mode - TInstructInform = record - Opcode: byte; //Code for instruction - nBytes: byte; //Num. of bytes of the instruction. - Cycles: byte; //Num. of cycles the instruction takes. - optCycles: string; //Extra options in Num. of cycles. - end; - - //Record for a 6502 instruction - - { TP6502Instruct } - - TP6502Instruct = object - public - //Name of the instruction - name: string[3]; - //Address Modes supported - addressModes: TP6502AddModes; - //Information for each Address Mode supported - instrInform: array[TP6502AddMode] of TInstructInform; - public - procedure Init(name0: string); - procedure AddAddressMode(aMode: TP6502AddMode; Opcode, nBytes, nCycles: Byte; - optCycles: string); - end; - - //Indica el destino de la instrucción - TPIC16destin = ( - toW = %00000000, //al acumulador - toF = %10000000 //a memoria - ); - - - -const //Constants of address and bit positions for some registers - _STATUS = $03; - _C = 0; - _Z = 2; - _RP0 = 5; - _RP1 = 6; -// _IRP = 7; -type - {Objeto que representa al hardware de un PIC de la serie 16} - { TP6502 } - TP6502 = class(TPicCore) - public //Campos para desensamblar instrucciones - idIns: TP6502Inst; //ID de Instrucción. - modIns: TP6502AddMode; //Modo de direccionamiento - parIns: word; //Parámetro de instrucción. Válido solo en algunas instrucciones. - b_ : byte; //Bit destino. Válido solo en algunas instrucciones. - k_ : word; //Parámetro Literal. Válido solo en algunas instrucciones. - private //Campos para procesar instrucciones - function GetINTCON: byte; - function GetINTCON_GIE: boolean; - function GetSTATUS: byte; - function GetSTATUS_C: boolean; - function GetSTATUS_DC: boolean; - function GetSTATUS_IRP: boolean; - function GetSTATUS_Z: boolean; - procedure SetINTCON_GIE(AValue: boolean); - procedure SetSTATUS_C(AValue: boolean); - procedure SetSTATUS_DC(AValue: boolean); - procedure SetSTATUS_IRP(AValue: boolean); - procedure SetSTATUS_Z(AValue: boolean); - procedure SetFRAM(value: byte); - function GetFRAM: byte; - public //Campos que modelan a los registros internos - W : byte; //Registro de trabajo - PC : TWordRec; //PC as record to fast access for bytes - PCLATH : byte; //Contador de Programa H - STKPTR : 0..7; //Puntero de pila - STACK : array[0..7] of word; - property STATUS: byte read GetSTATUS; - property STATUS_Z: boolean read GetSTATUS_Z write SetSTATUS_Z; - property STATUS_C: boolean read GetSTATUS_C write SetSTATUS_C; - property STATUS_DC: boolean read GetSTATUS_DC write SetSTATUS_DC; - property STATUS_IRP: boolean read GetSTATUS_IRP write SetSTATUS_IRP; - property INTCON: byte read GetINTCON; - property INTCON_GIE: boolean read GetINTCON_GIE write SetINTCON_GIE; - property FRAM: byte read GetFRAM write SetFRAM; - public //Execution control - function CurInstruction: TP6502Inst; - procedure Exec(aPC: word); override; //Ejecuta la instrucción en la dirección indicada. - procedure Exec; override; //Ejecuta instrucción actual - procedure ExecTo(endAdd: word); override; //Ejecuta hasta cierta dirección - procedure ExecStep; override; //Execute one instruction considering CALL as one instruction - procedure ExecNCycles(nCyc: integer; out stopped: boolean); override; //Ejecuta hasta cierta dirección - procedure Reset; override; - function ReadPC: dword; override; - procedure WritePC(AValue: dword); override; - public //Memories - procedure Decode(const opCode: word); //decodifica instrucción - function Disassembler(const opCode, par1, par2: byte; out nBytesProc: byte; - useVarName: boolean=false): string; //Desensambla la instrucción actual - function DisassemblerAt(addr: word; out nBytesProc: byte; useVarName: boolean - ): string; override; - public //Funciones para la memoria RAM - function GetFreeByte(out addr: word; shared: boolean): boolean; - function GetFreeBytes(const size: integer; var addr: word): boolean; //obtiene una dirección libre - function TotalMemRAM: word; //devuelve el total de memoria RAM - function UsedMemRAM: word; //devuelve el total de memoria RAM usada - procedure ExploreUsed(rutExplorRAM: TPICRutExplorRAM); //devuelve un reporte del uso de la RAM - function ValidRAMaddr(addr: word): boolean; //indica si una posición de memoria es válida - function BankToAbsRAM(const offset, bank: byte): word; //devuelve dirección absoluta - procedure AbsToBankRAM(const AbsAddr: word; var offset, bank: byte); //convierte dirección absoluta - public //Métodos para codificar instrucciones de acuerdo a la sintaxis - procedure useRAM; - procedure codAsmFD(const inst: TP6502Inst; addMode: TP6502AddMode; param: word); - function codInsert(iflash0, nInsert, nWords: integer): boolean; - public //Métodos adicionales - function FindOpcode(Op: string): TP6502Inst; //busca Opcode - procedure GenHex(hexFile: string; ConfigWord: integer = - 1); //genera un archivo hex - procedure DumpCode(lOut: TStrings; incAdrr, incCom, incVarNam: boolean); //vuelva en código que contiene - public //Initialization - constructor Create; override; - destructor Destroy; override; - end; - -var //variables globales - //mnemónico de las instrucciones - PIC16InstName: array[low(TP6502Inst)..high(TP6502Inst)] of TP6502Instruct; - -implementation - -{ TP6502Instruct } - -procedure TP6502Instruct.Init(name0: string); -//Initialize the instruction. Must be called before AddAddressMode(). -begin - name := name0; //Set - addressModes:= []; //Clear -end; -procedure TP6502Instruct.AddAddressMode(aMode: TP6502AddMode; - Opcode, nBytes, nCycles: Byte; - optCycles: string); -{Add a new Address Mode including additional information. -"optCycles" is a flag and indicate aditional considerations on cycles: - -'*' -> Add 1 to cycles if page boundery is crossed - -'**' -> Add 1 to cycles if branch occurs on same page - Add 2 to cycles if branch occurs to different page -} -begin - addressModes := addressModes + [aMode]; //Register Mode - //Add information - instrInform[aMode].Opcode:= Opcode; - instrInform[aMode].nBytes:= nBytes; - instrInform[aMode].Cycles:= nCycles; - instrInform[aMode].optCycles := optCycles; -end; - -{ TP6502 } -procedure TP6502.useRAM; -{Marca la posición actual, como usada, e incrementa el puntero iFlash. S ihay error, -actualiza el campo "MsjError"} -begin - //Protección de desborde - if iRam >= MaxFlash then begin - MsjError := 'FLASH Memory limit exceeded.'; - exit; - end; - ram[iRam].used := true; //marca como usado - inc(iRam); -end; -procedure TP6502.codAsmFD(const inst: TP6502Inst; addMode: TP6502AddMode; param: word); -{Codifica las instrucciones orientadas a registro, con sintAxis: NEMÓNICO f,d} -var - rInst: TP6502Instruct; -begin - rInst := PIC16InstName[inst]; - //Write OpCode - ram[iRam].value := rInst.instrInform[addMode].Opcode; - useRAM; //marca como usado e incrementa puntero. - //Codifica parámetros - case addMode of - aImplied_, aAcumulat:; //No tiene parámetros - aImmediat: begin - ram[iRam].value := lo(param); //escribe parámetro - useRAM; - end; - aAbsolute:begin - ram[iRam].value := lo(param); - useRAM; - ram[iRam].value := hi(param); - useRAM; - end; - aZeroPage:begin - ram[iRam].value := lo(param); - useRAM; - end; - aRelative:begin - ram[iRam].value := lo(param); - useRAM; - end; - aIndirect:begin - ram[iRam].value := lo(param); - useRAM; - ram[iRam].value := hi(param); - useRAM; - end; - aAbsolutX:begin - ram[iRam].value := lo(param); - useRAM; - ram[iRam].value := hi(param); - useRAM; - end; - aAbsolutY:begin - ram[iRam].value := lo(param); - useRAM; - ram[iRam].value := hi(param); - useRAM; - end; - aZeroPagX:begin - ram[iRam].value := lo(param); - useRAM; - end; - aZeroPagY:begin - ram[iRam].value := lo(param); - useRAM; - end; - aIdxIndir:begin - ram[iRam].value := lo(param); - useRAM; - end; - aIndirIdx:begin - ram[iRam].value := lo(param); - useRAM; - end; - else - raise Exception.Create('Implementation Error.'); - end; -end; -function TP6502.codInsert(iflash0, nInsert, nWords: integer): boolean; -{Inserta en la posición iflash0, "nInsert" palabras, desplazando "nWords" palabras. -Al final debe quedar "nInsert" palabras de espacio libre en iflash0. -Si hay error devuelve FALSE.} -var - i: Integer; -begin - Result := True; //By default - if iRam+nInsert+nWords-1> MaxFlash then begin - //Overflow on address - exit(false); - end; - for i:= iRam + nInsert + nWords -1 downto iRam + nWords do begin - ram[i] := ram[i-nInsert]; - end; -end; -//procedure TP6502.BTFSC_sw_BTFSS(iflash0: integer); -//{Exchange instruction i_BTFSC to i_BTFSS, or viceversa, in the specified address.} -//begin -// //Solo necesita cambiar el bit apropiado -// flash[iFlash0].value := flash[iFlash0].value XOR %10000000000; -//end; -function TP6502.FindOpcode(Op: string): TP6502Inst; -{Busca una cádena que represente a una instrucción (Opcode). Si encuentra devuelve - el identificador de instrucción . Si no encuentra devuelve "i_Inval". } -var - idInst: TP6502Inst; - tmp: String; -begin - tmp := UpperCase(Op); - for idInst := low(TP6502Inst) to high(TP6502Inst) do begin - if PIC16InstName[idInst].name = tmp then begin - Result := idInst; - exit; - end; - end; - //No encontró - Result := i_Inval; -end; -//Campos para procesar instrucciones -function TP6502.GetSTATUS: byte; -begin - Result := ram[_STATUS].dvalue; -end; -function TP6502.GetSTATUS_Z: boolean; -begin - Result := (ram[_STATUS].dvalue and %00000100) <> 0; -end; -procedure TP6502.SetSTATUS_Z(AValue: boolean); -begin - if AVAlue then ram[_STATUS].dvalue := ram[_STATUS].dvalue or %00000100 - else ram[_STATUS].dvalue := ram[_STATUS].dvalue and %11111011; -end; -function TP6502.GetSTATUS_C: boolean; -begin - Result := (ram[_STATUS].dvalue and %00000001) <> 0; -end; -procedure TP6502.SetSTATUS_C(AValue: boolean); -begin - if AVAlue then ram[_STATUS].dvalue := ram[_STATUS].dvalue or %00000001 - else ram[_STATUS].dvalue := ram[_STATUS].dvalue and %11111110; -end; -function TP6502.GetSTATUS_DC: boolean; -begin - Result := (ram[_STATUS].dvalue and %00000010) <> 0; -end; -procedure TP6502.SetSTATUS_DC(AValue: boolean); -begin - if AVAlue then ram[_STATUS].dvalue := ram[_STATUS].dvalue or %00000010 - else ram[_STATUS].dvalue := ram[_STATUS].dvalue and %11111101; -end; -function TP6502.GetSTATUS_IRP: boolean; -begin - Result := (ram[_STATUS].dvalue and %10000000) <> 0; -end; -procedure TP6502.SetSTATUS_IRP(AValue: boolean); -begin - if AVAlue then ram[_STATUS].dvalue := ram[_STATUS].dvalue or %10000000 - else ram[_STATUS].dvalue := ram[_STATUS].dvalue and %01111111; -end; -function TP6502.GetINTCON: byte; -begin - Result := ram[$0B].dvalue; -end; -function TP6502.GetINTCON_GIE: boolean; -begin - Result := (ram[$0B].dvalue and %10000000) <> 0; -end; -procedure TP6502.SetINTCON_GIE(AValue: boolean); -begin - if AVAlue then ram[$0B].dvalue := ram[$0B].dvalue or %10000000 - else ram[$0B].dvalue := ram[$0B].dvalue and %01111111; -end; -procedure TP6502.SetFRAM(value: byte); -{Escribe en la RAM; en la dirección global f_, el valor "value" -Para determinar el valor real de la dirección, se toma en cuenta los bits de STATUS} -begin - if parIns = 0 then begin - //Caso especial de direccionamiento indirecto - if STATUS_IRP then begin - ram[ram[04].value + $100].value := value; - end else begin - ram[ram[04].value].value := value; - end; - exit; - end; - {Se escribe aplicando la máscara de bits implementados. Se podría usra la máscara en - lectura o escritura, pero se prefiere hacerlo en escritura, porque se espera que se - hagan menos operaciones de escritura que lectura.} - case STATUS and %01100000 of - %00000000: ram[parIns ].value := value; - %00100000: ram[parIns+PICBANKSIZE ].value := value; - %01000000: ram[parIns+PICBANKSIZE*2].value := value; - %01100000: ram[parIns+PICBANKSIZE*3].value := value; - end; -end; -function TP6502.GetFRAM: byte; -{Devuelve el valor de la RAM, de la posición global f_. -Para determinar el valor real de la dirección, se toma en cuenta los bits de STATUS} -begin - if parIns = 0 then begin - //Caso especial de direccionamiento indirecto - if STATUS_IRP then begin - Result := ram[ram[04].value + $100].value; - end else begin - Result := ram[ram[04].value].value; - end; - exit; - end; - case STATUS and %01100000 of - %00000000: Result := ram[parIns ].value; - %00100000: Result := ram[parIns+ PICBANKSIZE ].value; - %01000000: Result := ram[parIns+ PICBANKSIZE*2].value; - %01100000: Result := ram[parIns+ PICBANKSIZE*3].value; - end; -end; -procedure TP6502.Decode(const opCode: word); -{Decode the value of "opCode" and update: -* "idIns" -> Instruction ID -* "modIns" -> Address Mode -} -var - i : TP6502Inst; - j : TP6502AddMode; - inst: TP6502Instruct; - iInfom: TInstructInform; -begin - //Search the Opcode - for i := low(TP6502Inst) to high(TP6502Inst) do begin - inst := PIC16InstName[i]; - for j := low(TP6502AddMode) to high(TP6502AddMode) do begin - iInfom := inst.instrInform[j]; - if iInfom.Opcode = opCode then begin - idIns := i; - modIns := j; - end; - end; - end; -end; -function TP6502.Disassembler(const opCode, par1, par2: byte; - out nBytesProc: byte; - useVarName: boolean = false): string; -{Disassemble the instruction indicated in "Opcode". If the instruction is multibyte -it will be used "par1" and "par2" according to the intruction length, which is returned -in "nBytesProc". -Global variables used: "idIns", "modIns". -"useVarName" -> Flag to use the name of the variable instead of only the address. - Valid only when a variAble name exists in his address. -} -var - nemo: String; - f: word; -begin - Decode(opCode); //Decode instruction. Update: "idIns", "modIns". - nemo := trim(PIC16InstName[idIns].name) + ' '; - case modIns of - aImplied_: begin - nBytesProc := 1; //No parameters needed - end; - aAcumulat: begin - nBytesProc := 1; //No parameters needed - end; - aImmediat: begin - Result := nemo + '#$'+IntToHex(par1,2); - nBytesProc := 2; - end; - aAbsolute: begin - Result := nemo + '$'+IntToHex(par1 + par2*256, 4); - nBytesProc := 3; - end; - aZeroPage: begin - Result := nemo + '$'+IntToHex(par1, 2); - nBytesProc := 2; - end; - aRelative: begin - Result := nemo + '$'+IntToHex(par1, 2); - nBytesProc := 2; - end; - aIndirect: begin - Result := nemo + '$('+IntToHex(par1 + par2*256, 4)+')'; - nBytesProc := 3; - end; - aAbsolutX: begin - Result := nemo + '$'+IntToHex(par1 + par2*256, 4)+',X'; - nBytesProc := 3; - end; - aAbsolutY: begin - Result := nemo + '$'+IntToHex(par1 + par2*256, 4)+',Y'; - nBytesProc := 3; - end; - aZeroPagX: begin - Result := nemo + '$'+IntToHex(par1, 2)+',X'; - nBytesProc := 3; - end; - aZeroPagY: begin - Result := nemo + '$'+IntToHex(par1, 2)+',Y'; - nBytesProc := 3; - end; - aIdxIndir: begin - Result := nemo + '$('+IntToHex(par1, 2)+',X)'; - nBytesProc := 2; - end; - aIndirIdx: begin - Result := nemo + '$('+IntToHex(par1, 2)+'),Y'; - nBytesProc := 3; - end; - end; -end; -function TP6502.DisassemblerAt(addr: word; out nBytesProc: byte; - useVarName: boolean): string; -{Disassembler the instruction located at "addr"} -var - valOp: Word; -begin - Result := Disassembler(ram[addr].value, - ram[addr+1].value, - ram[addr+2].value, nBytesProc, useVarName); -end; -function TP6502.CurInstruction: TP6502Inst; -{Resturn the instruction pointed by PC, in this moment.} -begin - Decode(ram[PC.W].value); //decode instruction - Result := idIns; -end; -procedure TP6502.Exec; -{Execute the current instruction.} -begin - Exec(PC.W); -end; -procedure TP6502.Exec(aPC: word); -{Ejecuta la instrución actual con dirección "pc". -Falta implementar las operaciones, cuando acceden al registro INDF, el Watchdog timer, -los contadores, las interrupciones} -var - opc: byte; - msk, resNib: byte; - nCycles, nBytes: byte; - resInt : integer; -begin - //Decodifica instrucción - opc := ram[aPC].value; - Decode(opc); //Decode instruction - nCycles := PIC16InstName[idIns].instrInform[modIns].Cycles; - nBytes := PIC16InstName[idIns].instrInform[modIns].nBytes; - - case idIns of - i_ADC:; //add with carry - i_AND:; //and (with accumulator) - i_ASL:; //arithmetic shift left - i_BCC:; //branch on carry clear - i_BCS:; //branch on carry set - i_BEQ:; //branch on equal (zero set) - i_BIT:; //bit test - i_BMI:; //branch on minus (negative set) - i_BNE:; //branch on not equal (zero clear) - i_BPL:; //branch on plus (negative clear) - i_BRK:; //break / interrupt - i_BVC:; //branch on overflow clear - i_BVS:; //branch on overflow set - i_CLC:; //clear carry - i_CLD:; //clear decimal - i_CLI:; //clear interrupt disable - i_CLV:; //clear overflow - i_CMP:; //compare (with accumulator) - i_CPX:; //compare with X - i_CPY:; //compare with Y - i_DEC:; //decrement - i_DEX:; //decrement X - i_DEY:; //decrement Y - i_EOR:; //exclusive or (with accumulator) - i_INC:; //increment - i_INX:; //increment X - i_INY:; //increment Y - i_JMP:; //jump - i_JSR:; //jump subroutine - i_LDA:; //load accumulator - i_LDX:; //load X - i_LDY:; //load Y - i_LSR:; //logical shift right - i_NOP:; //no operation - i_ORA:; //or with accumulator - i_PHA:; //push accumulator - i_PHP:; //push processor status (SR) - i_PLA:; //pull accumulator - i_PLP:; //pull processor status (SR) - i_ROL:; //rotate left - i_ROR:; //rotate right - i_RTI:; //return from interrupt - i_RTS:; //return from subroutine - i_SBC:; //subtract with carry - i_SEC:; //set carry - i_SED:; //set decimal - i_SEI:; //set interrupt disable - i_STA:; //store accumulator - i_STX:; //store X - i_STY:; //store Y - i_TAX:; //transfer accumulator to X - i_TAY:; //transfer accumulator to Y - i_TSX:; //transfer stack pointer to X - i_TXA:; //transfer X to accumulator - i_TXS:; //transfer X to stack pointer - i_TYA:; //transfer Y to accumulator - i_Inval: begin - MsjError := 'Invalid Opcode'; - end; - end; - -{ i_ADDWF: begin - resByte := FRAM; - resWord := W + resByte; - resNib := (W and $0F) + (resByte and $0F); - if modIns = toF then begin - FRAM := resWord and $FF; - end else begin //toW - w := resWord and $FF; - end; - STATUS_Z := (resWord and $ff) = 0; - STATUS_C := (resWord > 255); - STATUS_DC := (resNib > 15); - end; - i_ANDWF: begin - resByte := W and FRAM; - if modIns = toF then begin - FRAM := resByte; - end else begin //toW - w := resByte; - end; - STATUS_Z := resByte = 0; - end; - i_CLRF: begin - FRAM := 0; - STATUS_Z := true; - end; - i_CLRW: begin - W := 0; - STATUS_Z := true; - end; - i_COMF : begin - resByte := not FRAM; - if modIns = toF then begin - FRAM := resByte; - end else begin //toW - w := resByte; - end; - STATUS_Z := resByte = 0; - end; - i_DECF : begin - resByte := FRAM; - if resByte = 0 then resByte := $FF else dec(resByte); - if modIns = toF then begin - FRAM := resByte; - end else begin //toW - w := resByte; - end; - STATUS_Z := resByte = 0; - end; - i_DECFSZ: begin - resByte := FRAM; - if resByte = 0 then resByte := $FF else dec(resByte); - if modIns = toF then begin - FRAM := resByte; - end else begin //toW - w := resByte; - end; - STATUS_Z := resByte = 0; - if STATUS_Z then begin - Inc(PC.W); //Jump one instrucción - Inc(nClck); //In this case it takes one more cicle - end; - end; - i_INCF: begin - resByte := FRAM; - if resByte = 255 then resByte := 0 else inc(resByte); - if modIns = toF then begin - FRAM := resByte; - end else begin //toW - w := resByte; - end; - STATUS_Z := resByte = 0; - end; - i_INCFSZ: begin - resByte := FRAM; - if resByte = 255 then resByte := 0 else inc(resByte); - if modIns = toF then begin - FRAM := resByte; - end else begin //toW - w := resByte; - end; - STATUS_Z := resByte = 0; - if STATUS_Z then begin - Inc(PC.W); //Jump one instrucción - Inc(nClck); //In this case it takes one more cicle - end; - end; - i_IORWF: begin - resByte := W or FRAM; - if modIns = toF then begin - FRAM := resByte; - end else begin //toW - w := resByte; - end; - STATUS_Z := resByte <> 0; - end; - i_MOVF: begin - resByte := FRAM; - if modIns = toF then begin - //no mueve, solo verifica - STATUS_Z := (resByte = 0); - end else begin //toW - w := resByte; - STATUS_Z := (resByte = 0); - end; - end; - i_MOVWF: begin - FRAM := W; //escribe a donde esté mapeado, (si está mapeado) - if parIns = $02 then begin //Es el PCL - PC.H := PCLATH; //Cuando se escribe en PCL, se carga PCH con PCLATH - end; - end; - i_NOP: begin - end; - i_RLF: begin - resByte := FRAM; - bit7 := resByte and $80; //guarda bit 7 - resByte := (resByte << 1) and $ff; //desplaza - //pone C en bit bajo - if STATUS_C then begin //C era 1 - resByte := resByte or $01; //pone a 1 el bit 0 - end else begin //C era 0 - //no es necesario agregarlo, porque por defecto se agrega 0 - end; - //Actualiza C - if bit7 = 0 then STATUS_C := false - else STATUS_C := true; - if modIns = toF then begin - FRAM := resByte; - end else begin //toW - w := resByte; - end; - end; - i_RRF: begin - resByte := FRAM; - bit0 := resByte and $01; //guarda bit 0 - resByte := resByte >> 1; //desplaza - //pone C en bit alto - if STATUS_C then begin //C era 1 - resByte := resByte or $80; //pone a 1 el bit 0 - end else begin //C era 0 - //no es necesario agregarlo, porque por defecto se agrega 0 - end; - //Actualiza C - if bit0 = 0 then STATUS_C := false - else STATUS_C := true; - if modIns = toF then begin - FRAM := resByte; - end else begin //toW - w := resByte; - end; - end; - i_SUBWF: begin - resByte := FRAM; - resInt := resByte - W; - if modIns = toF then begin - FRAM := resInt and $FF; - end else begin //toW - w := resInt and $FF; - end; - STATUS_Z := (resInt = 0); - if resInt < 0 then STATUS_C := false //negativo - else STATUS_C := true; - resInt := (resByte and $0F) - (W and $0F); - if resInt < 0 then STATUS_DC := false //negativo - else STATUS_DC := true; - end; - i_SWAPF: begin - resByte := FRAM; - FRAM := (resByte >> 4) or (resByte << 4); - end; - i_XORWF: begin - resByte := W xor FRAM; - if modIns = toF then begin - FRAM := resByte; - end else begin //toW - w := resByte; - end; - STATUS_Z := resByte <> 0; - end; - //BIT-ORIENTED FILE REGISTER OPERATIONS - i_BCF: begin - msk := $1 << b_; - msk := not msk; - FRAM := FRAM and msk; - end; - i_BSF: begin - msk := $1 << b_; - FRAM := FRAM or msk;// b_ - end; - i_BTFSC: begin - msk := $1 << b_; - if (FRAM and msk) = 0 then begin - Inc(PC.W); //Jump one instrucción - Inc(nClck); //In this case it takes one more cicle - end; - end; - i_BTFSS: begin - msk := $1 << b_; - if (FRAM and msk) <> 0 then begin - Inc(PC.W); //Jump one instrucción - Inc(nClck); //In this case it takes one more cicle - end; - end; - //LITERAL AND CONTROL OPERATIONS - i_ADDLW: begin - resWord := W + k_; - resNib := (W and $0F) + (k_ and $0F); - w := resWord and $FF; - STATUS_Z := (resWord and $ff) = 0; - STATUS_C := (resWord > 255); - STATUS_DC := (resNib > 15); - end; - i_ANDLW: begin - resByte := W and K_; - w := resByte; - STATUS_Z := resByte = 0; - end; - i_CALL: begin - //Guarda dirección en Pila - STACK[STKPTR] := PC.W; - if STKPTR = 7 then begin - //Desborde de pila - STKPTR := 0; - if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on CALL OpCode at $' + IntToHex(aPC,4)); - end else begin - STKPTR := STKPTR +1; - end; - PC.W := k_; //Takes the 11 bits from k - PC.H := PC.H or (PCLATH and %00011000); //And complete with bits 3 and 4 of PCLATH - Inc(nClck,2); //This instruction takes two cicles - exit; - end; - i_CLRWDT: begin - end; - i_GOTO: begin - PC.W := k_; //Takes the 11 bits from k - PC.H := PC.H or (PCLATH and %00011000); //And complete with bits 3 and 4 of PCLATH - Inc(nClck,2); //This instruction takes two cicles - exit; - end; - i_IORLW: begin - resByte := W or k_; - w := resByte; - STATUS_Z := resByte <> 0; - end; - i_MOVLW: begin - W := k_; - end; - i_RETFIE: begin - //Saca dirección en Pila - if STKPTR = 0 then begin - //Desborde de pila - STKPTR := 7; - if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on RETFIE OpCode at $' + IntToHex(aPC,4)); - end else begin - STKPTR := STKPTR - 1; - end; - PC.W := STACK[STKPTR]; //Should be 13 bits - Inc(nClck); //Esta instrucción toma un ciclo más - //Activa GIE - INTCON_GIE := true; - end; - i_RETLW: begin - //Saca dirección en Pila - if STKPTR = 0 then begin - //Desborde de pila - STKPTR := 7; - if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on RETLW OpCode at $' + IntToHex(aPC,4)); - end else begin - STKPTR := STKPTR - 1; - end; - PC.W := STACK[STKPTR]; //Should be 13 bits - Inc(nClck); //Esta instrucción toma un ciclo más - //Fija valor en W - W := k_; - end; - i_RETURN: begin - //Saca dirección en Pila - if STKPTR = 0 then begin - //Desborde de pila - STKPTR := 7; - if OnExecutionMsg<>nil then OnExecutionMsg('Stack Overflow on RETURN OpCode at $' + IntToHex(aPC,4)); - end else begin - STKPTR := STKPTR - 1; - end; - PC.W := STACK[STKPTR]; //Should be 13 bits - Inc(nClck); //Esta instrucción toma un ciclo más - end; - i_SLEEP: begin - end; - i_SUBLW: begin - resInt := k_ - W; - w := resInt and $FF; - STATUS_Z := (resInt = 0); - if resInt < 0 then STATUS_C := false //negativo - else STATUS_C := true; - resInt := (k_ and $0F) - (W and $0F); - if resInt < 0 then STATUS_DC := false //negativo - else STATUS_DC := true; - end; - i_XORLW: begin - resByte := W xor k_; - w := resByte; - STATUS_Z := resByte <> 0; - end; - i_Inval: begin - MsjError := 'Invalid Opcode'; - end; - end; -} - //Increase counters - Inc(PC.W, nBytes); - Inc(nClck, nCycles); -end; -procedure TP6502.ExecTo(endAdd: word); -{Ejecuta las instrucciones secuencialmente, desde la instrucción actual, hasta que el -contador del programa, sea igual a la dirección "endAdd".} -begin - //Hace una primera ejecución, sin verificar Breakpoints - Exec(PC.W); - //Ejecuta cíclicamnente - while PC.W <> endAdd do begin - if ram[PC.W].breakPnt then begin - //Encontró un BreakPoint, sale sin ejecutar esa instrucción - if OnExecutionMsg<>nil then OnExecutionMsg('Stopped for breakpoint.'); - exit; - end; - //Ejecuta - Exec(PC.W); - //Debe haber una forma de salir si es un lazo infinito - //if (nClck and $800000) = $800000 then begin - //end; - end; -end; -procedure TP6502.ExecStep; -begin - if CurInstruction = i_JSR then begin - ExecTo(PC.W+3); //Ejecuta hasta la sgte. instrucción, salta el JSR - end else begin - Exec; - end; -end; -procedure TP6502.ExecNCycles(nCyc: integer; out stopped: boolean); -{Ejecuta el número de ciclos indicados, o hasta que se produzca alguna condición -externa, que puede ser: -* Se encuentre un Punto de Interrupción. -* Se detecta la señal, de detenerse. -* Se genere algún error en la ejecución. -* Se ejecuta la instrucción i_SLEEP. -la bandera "stopped", indica que se ha detendio la ejecución sin completar la cantidad -de instrucciones requeridas. -Normalmente Se ejecutará el número de ciclos indicados, pero en algunos casos se -ejecutará un ciclo más, debido a que algunas instrucciones toman dos ciclos.} -var - clkEnd: Int64; - _pc: word; -begin - clkEnd := nClck + nCyc; //Valor final del contador - while nClck < clkEnd do begin - _pc := PC.W; - if ram[_pc].breakPnt then begin - //Encontró un BreakPoint, sale sin ejecutar esa instrucción - if OnExecutionMsg<>nil then OnExecutionMsg('Stopped for breakpoint.'); - stopped := true; - exit; - end; - if not ram[_pc].used then begin - //Encontró un BreakPoint, sale sin ejecutar esa instrucción - if OnExecutionMsg<>nil then OnExecutionMsg('Stopped for executing unused code.'); - stopped := true; - exit; - end; - if CommStop then begin - //Se detectó el comando STOP - if OnExecutionMsg<>nil then OnExecutionMsg('Stopped for STOP command.'); - stopped := true; - exit; - end; - //Ejecuta - Exec(_pc); - end; - stopped := false; -end; -procedure TP6502.Reset; -//Reinicia el dipsoitivo -var - i: Integer; -begin - PC.W := 0; - PCLATH := 0; - W := 0; - STKPTR := 0; //Posición inicial del puntero de pila - nClck := 0; //Inicia contador de ciclos - CommStop := false; //Limpia bandera - //Limpia solamente el valor inicial, no toca los otros campos - for i:=0 to high(ram) do begin - ram[i].dvalue := $00; - end; - ram[_STATUS].dvalue := %00011000; //STATUS -end; -function TP6502.ReadPC: dword; -begin - Result := PC.W; -end; -procedure TP6502.WritePC(AValue: dword); -begin - PC.W := AValue; -end; -//Funciones para la memoria RAM -function TP6502.GetFreeByte(out addr: word; shared: boolean): boolean; -{Devuelve una dirección libre de la memoria flash. -"Shared" indica que se marcará el bit como de tipo "Compartido", y se usa para el -caso en que se quiera comaprtir la misma posición para diversos variables. -Si encuentra espacio, devuelve TRUE.} -var - i: Integer; - maxRam: word; -begin - Result := false; //valor inicial - maxRam := NumBanks * PICBANKSIZE; //posición máxima - //Realmente debería explorar solo hasta la dirección implementada, por eficiencia - for i:=0 to maxRam-1 do begin - if (ram[i].state = cs_impleGPR) and (not ram[i].used) then begin - //Esta dirección está libre - ram[i].used := true; //marca como usado - if shared then begin - ram[i].shared := true; //Marca como compartido - end; - addr := i; - //Notar que la posición de memoria puede estar mapeada a otro banco. - Result := true; //indica que encontró espacio - exit; - end; - end; -end; -function TP6502.GetFreeBytes(const size: integer; var addr: word): boolean; -{Devuelve una dirección libre de la memoria flash (y el banco) para ubicar un bloque - del tamaño indicado. Si encuentra espacio, devuelve TRUE. - El tamaño se da en bytes, pero si el valor es negativo, se entiende que es en bits.} -var - i: word; - maxRam: Word; -begin - Result := false; //valor por defecto - if size=0 then exit; - maxRam := word(NumBanks * PICBANKSIZE) - 1; - for i:=0 to maxRam do begin //verifica 1 a 1, por seguridad - if HaveConsecRAM(i, size, maxRam) then begin - //encontró del tamaño buscado - UseConsecRAM(i, size); //marca como usado - addr := i; - Result := true; //indica que encontró espacio - exit; - end; - end; -end; -function TP6502.TotalMemRAM: word; -{Devuelve el total de memoria RAM disponible} -var - i: Integer; -begin - Result := 0; - for i := 0 to word(NumBanks * PICBANKSIZE) - 1 do begin - if ram[i].AvailGPR then begin - Result := Result + 1; - end; - end; -end; -function TP6502.UsedMemRAM: word; -{Devuelve el total de memoria RAM usada} -var - i: Integer; -begin - Result := 0; - for i := 0 to word(NumBanks * PICBANKSIZE) - 1 do begin - if ram[i].AvailGPR and (ram[i].used) then begin - //Notar que "AvailGPR" asegura que no se consideran registros maepados - Result := Result + 1; - end; - end; -end; -procedure TP6502.ExploreUsed(rutExplorRAM: TPICRutExplorRAM); -{Genera un reporte de uso de RAM} -var - i: Integer; -begin - for i := 0 to word(NumBanks * PICBANKSIZE) - 1 do begin - if ram[i].AvailGPR and (ram[i].used) then begin - rutExplorRAM(i, 0, @ram[i]); - end; - end; -end; -function TP6502.ValidRAMaddr(addr: word): boolean; -{Indica si la dirección indicada es válida dentro del hardware del PIC} -begin - if addr > PICBANKSIZE*NumBanks then exit(false); //excede límite - exit(true); -end; -function TP6502.BankToAbsRAM(const offset, bank: byte): word; -{Convierte una dirección y banco a una dirección absoluta} -begin - Result := bank * PICBANKSIZE + offset; -end; -procedure TP6502.AbsToBankRAM(const AbsAddr: word; var offset, bank: byte); -{Convierte dirección absoluta a dirección en bancos} -begin - offset := AbsAddr and %01111111; - bank := AbsAddr >> 7; -end; -procedure TP6502.GenHex(hexFile: string; ConfigWord: integer = -1); -{Genera el archivo *.hex, a partir de los datos almacenados en la memoria -FLASH. -Actualiza los campos, minUsed y maxUsed.} -var - cfg, tmp: String; - iHex: word; //Índice para explorar - dat: String; //Cadena de dígitos hexadecimales - addr: word; //Dirección de inicio -const - MAX_INS_HEX = 8; //Número máximo de instrucciones que devuelve por pasada - - function ExtractHex(out Addre: word): string; - {Devuelve una cadena (de longitud que varía desde 0, hasta MAX_INS_HEX*4 caracteres) - con valores en hexadecimal de isntrucciones, consecutivas usadas, en le memoria FLASH. - La lectura se hace a partir de iHex, y los caracteres en hexadecimal se escriben en 4 - dígitos, en la misma forma que se usan para los archivos *.HEX. - En "Addr" devuelve la dirección absoluta de inicio desde donde lee. Con cada llamada, - devuelve los bloques consecutivos de datos. Si no hay más datos devuelve cadena vacía.} - var p1, p2: word; - cont, p: word; - tmp: String; - begin - Result := ''; - //Busca inicio de instrucciones usadas, desde la posición iHex - while (iHex=PICMAXFLASH then begin - //Llegó al final - exit; //sale con cadena nula - end; - //Ya encontró el inicio ahora busca celdas consecutivas - p1 := iHex; - Addre := p1; - cont := 2; //inicia contador - inc(iHex); //pasa al siguiente - while (iHex=PICMAXFLASH then begin - //Salió porque Llegó al final - p2 := PICMAXFLASH-1; - end else if cont>=MAX_INS_HEX then begin - //Salió porque llegó al máximo de celdas - if ram[iHex].used then begin - //La ultima celda estaba ocupada - p2 := iHex; - inc(iHex); //deja listo para la siguiente exploración - end else begin - //La ultima celda estaba ocupada - p2 := iHex-1; - //iHex, queda apuntando a la siguiente celda - end; - end else begin - //Salió porque encontró celda sin usar - p2 := iHex-1; - //iHex, queda apuntando a la siguiente celda - end; - //Ya tiene las dos posiciones - tmp := ''; - for p:=p1 to p2 do begin - if p1maxUsed then maxUsed := p2; //Actualiza - tmp := IntToHex(ram[p].value, 4); - Result +=copy(tmp,3,2) + copy(tmp,1,2); //se graba con los bytes invertidos - end; - end; - -begin - hexLines.Clear; //Se usará la lista hexLines - GenHexExAdd($0000); - //Prepara extracción de datos - minUsed := PICMAXFLASH; - maxUsed := 0; - iHex := 0; - //Inicia la extracción de código - dat := ExtractHex(addr); - while dat <>'' do begin - GenHexData(addr, dat); - dat := ExtractHex(addr); - end; - //Bits de configuración - tmp := ''; - if ConfigWord<>-1 then begin - //Se pide generar bits de configuración - {Los bits de configuración para la serie 16F, se almacenan en: -Config: 0x2007 (0x400E in the HEX file) -EEPROM: 0x2100 (0x4200 in the HEX file) } - cfg := IntToHex(ConfigWord and $FFFF, 4); - tmp +=copy(cfg,3,2) + copy(cfg,1,2); //se graba con los bytes invertidos - GenHexData($2007, tmp); - end; - GenHexEOF; //Fin de archivo - GenHexComm(self.Model); //Comentario - hexLines.SaveToFile(hexFile); //Genera archivo -end; -procedure TP6502.DumpCode(lOut: TStrings; incAdrr, incCom, incVarNam: boolean); -{Desensambla las instrucciones grabadas en el PIC. - Se debe llamar despues de llamar a GenHex(), para que se actualicen las variables} -var - i: Word; - lblLin, comLat, comLin, lin: String; - nBytes: byte; -begin - //Se supone que minUsed y maxUsed, ya deben haber sido actualizados. - i := minUsed; - while i <= maxUsed do begin - //Lee comentarios y etiqueta - lblLin := ram[i].topLabel; - comLat := ram[i].sideComment; - comLin := ram[i].topComment; - //Escribe etiqueta al inicio de línea - if lblLin<>'' then lOut.Add(lblLin+':'); - //Escribe comentario al inicio de línea - if incCom and (comLin<>'') then begin - lOut.Add(comLin); - end; - //Decodifica instrucción - lin := DisassemblerAt(i, nBytes, incVarNam); //Instrucción - i := i + nBytes; - //Verificas si incluye dirección física - if incAdrr then begin - lin := '0x'+IntToHex(i,3) + ' ' + lin; - end; - //Verifica si incluye comentario lateral - if incCom then begin - lin := lin + ' ' + comLat; - end; - lOut.Add(' ' + lin); - end; -end; -constructor TP6502.Create; -begin - inherited Create; - PICBANKSIZE := 128; //RAM bank size - PICMAXRAM := PICBANKSIZE * 4; //Máx RAM memory (4 banks) - PICPAGESIZE := 2048; - PICMAXFLASH := PICPAGESIZE * 4; //Máx Flash memeory (4 pages) - SetLength(ram, PICMAXRAM); - //Default hardware settings - NumBanks:=2; //Número de bancos de RAM. Por defecto se asume 2 - NumPages:=1; //Número de páginas de memoria Flash. Por defecto 1 - MaxFlash := PICPAGESIZE; //En algunos casos, puede ser menor al tamaño de una página - //inicia una configuración común - ClearMemRAM; - SetStatRAM($020, $04F, cs_impleGPR); - - //estado inicial - iRam := 0; //posición de inicio - ClearMemFlash; -end; -destructor TP6502.Destroy; -begin - inherited Destroy; -end; -procedure InitTables; -begin - /////////////////////////////////////////////////////////////////// - ////////////////// Set instructions information /////////////////// - // Based on the information from: - // http://www.masswerk.at/6502/6502_instruction_set.html - /////////////////////////////////////////////////////////////////// - - ////////////////////////////// ADC //////////////////////////////// - PIC16InstName[i_ADC].name := 'ADC'; //Add Memory to Accumulator with Carry - PIC16InstName[i_ADC].AddAddressMode(aImmediat,$69,2,2,''); - PIC16InstName[i_ADC].AddAddressMode(aZeroPage,$65,2,3,''); - PIC16InstName[i_ADC].AddAddressMode(aZeroPagX,$75,2,4,''); - PIC16InstName[i_ADC].AddAddressMode(aAbsolute,$6D,3,4,''); - PIC16InstName[i_ADC].AddAddressMode(aAbsolutX,$7D,3,4,'*'); - PIC16InstName[i_ADC].AddAddressMode(aAbsolutY,$79,3,4,'*'); - PIC16InstName[i_ADC].AddAddressMode(aIdxIndir,$61,2,6,''); - PIC16InstName[i_ADC].AddAddressMode(aIndirIdx,$71,2,5,'*'); - PIC16InstName[i_AND].name := 'AND'; //AND Memory with Accumulator - PIC16InstName[i_AND].AddAddressMode(aImmediat,$29,2,2,''); - PIC16InstName[i_AND].AddAddressMode(aZeroPage,$25,2,3,''); - PIC16InstName[i_AND].AddAddressMode(aZeroPagX,$35,2,4,''); - PIC16InstName[i_AND].AddAddressMode(aAbsolute,$2D,3,4,''); - PIC16InstName[i_AND].AddAddressMode(aAbsolutX,$3D,3,4,'*'); - PIC16InstName[i_AND].AddAddressMode(aAbsolutY,$39,3,4,'*'); - PIC16InstName[i_AND].AddAddressMode(aIdxIndir,$21,2,6,''); - PIC16InstName[i_AND].AddAddressMode(aIndirIdx,$31,2,5,'*'); - PIC16InstName[i_ASL].name := 'ASL'; //Shift Left One Bit (MemoryorAccumulator) - PIC16InstName[i_ASL].AddAddressMode(aAcumulat,$0A,1,2,''); - PIC16InstName[i_ASL].AddAddressMode(aZeroPage,$06,2,5,''); - PIC16InstName[i_ASL].AddAddressMode(aZeroPagX,$16,2,6,''); - PIC16InstName[i_ASL].AddAddressMode(aAbsolute,$0E,3,6,''); - PIC16InstName[i_ASL].AddAddressMode(aAbsolutX,$1E,3,7,''); - PIC16InstName[i_BCC].name := 'BCC'; //Branch on Carry Clear - PIC16InstName[i_BCC].AddAddressMode(aRelative,$90,2,2,'**'); - PIC16InstName[i_BCS].name := 'BCS'; //Branch on Carry Set - PIC16InstName[i_BCS].AddAddressMode(aRelative,$B0,2,2,'**'); - PIC16InstName[i_BEQ].name := 'BEQ'; //Branch on Result Zero - PIC16InstName[i_BEQ].AddAddressMode(aRelative,$F0,2,2,'**'); - PIC16InstName[i_BIT].name := 'BIT'; //Test Bits in Memory with Accumulator - PIC16InstName[i_BIT].AddAddressMode(aZeroPage,$24,2,3,''); - PIC16InstName[i_BIT].AddAddressMode(aAbsolute,$2C,3,4,''); - PIC16InstName[i_BMI].name := 'BMI'; //Branch on Result Minus - PIC16InstName[i_BMI].AddAddressMode(aRelative,$30,2,2,'**'); - PIC16InstName[i_BNE].name := 'BNE'; //Branch on Result not Zero - PIC16InstName[i_BNE].AddAddressMode(aRelative,$D0,2,2,'**'); - PIC16InstName[i_BPL].name := 'BPL'; //Branch on Result Plus - PIC16InstName[i_BPL].AddAddressMode(aRelative,$10,2,2,'**'); - PIC16InstName[i_BRK].name := 'BRK'; //Force Break - PIC16InstName[i_BRK].AddAddressMode(aImplied_,$00,1,7,''); - PIC16InstName[i_BVC].name := 'BVC'; //Branch on Overflow Clear - PIC16InstName[i_BVC].AddAddressMode(aRelative,$50,2,2,'**'); - PIC16InstName[i_BVS].name := 'BVS'; //Branch on Overflow Set - PIC16InstName[i_BVS].AddAddressMode(aRelative,$70,2,2,'**'); - PIC16InstName[i_CLC].name := 'CLC'; //Clear Carry Flag - PIC16InstName[i_CLC].AddAddressMode(aImplied_,$18,1,2,''); - PIC16InstName[i_CLD].name := 'CLD'; //Clear Decimal Mode - PIC16InstName[i_CLD].AddAddressMode(aImplied_,$D8,1,2,''); - PIC16InstName[i_CLI].name := 'CLI'; //Clear Interrupt Disable Bit - PIC16InstName[i_CLI].AddAddressMode(aImplied_,$58,1,2,''); - PIC16InstName[i_CLV].name := 'CLV'; //Clear Overflow Flag - PIC16InstName[i_CLV].AddAddressMode(aImplied_,$B8,1,2,''); - PIC16InstName[i_CMP].name := 'CMP'; //Compare Memory with Accumulator - PIC16InstName[i_CMP].AddAddressMode(aImmediat,$C9,2,2,''); - PIC16InstName[i_CMP].AddAddressMode(aZeroPage,$C5,2,3,''); - PIC16InstName[i_CMP].AddAddressMode(aZeroPagX,$D5,2,4,''); - PIC16InstName[i_CMP].AddAddressMode(aAbsolute,$CD,3,4,''); - PIC16InstName[i_CMP].AddAddressMode(aAbsolutX,$DD,3,4,'*'); - PIC16InstName[i_CMP].AddAddressMode(aAbsolutY,$D9,3,4,'*'); - PIC16InstName[i_CMP].AddAddressMode(aIdxIndir,$C1,2,6,''); - PIC16InstName[i_CMP].AddAddressMode(aIndirIdx,$D1,2,5,'*'); - PIC16InstName[i_CPX].name := 'CPX'; //Compare Memory and Index X - PIC16InstName[i_CPX].AddAddressMode(aImmediat,$E0,2,2,''); - PIC16InstName[i_CPX].AddAddressMode(aZeroPage,$E4,2,3,''); - PIC16InstName[i_CPX].AddAddressMode(aAbsolute,$EC,3,4,''); - PIC16InstName[i_CPY].name := 'CPY'; //Compare Memory and Index Y - PIC16InstName[i_CPY].AddAddressMode(aImmediat,$C0,2,2,''); - PIC16InstName[i_CPY].AddAddressMode(aZeroPage,$C4,2,3,''); - PIC16InstName[i_CPY].AddAddressMode(aAbsolute,$CC,3,4,''); - PIC16InstName[i_DEC].name := 'DEC'; //Decrement Memory by One - PIC16InstName[i_DEC].AddAddressMode(aZeroPage,$C6,2,5,''); - PIC16InstName[i_DEC].AddAddressMode(aZeroPagX,$D6,2,6,''); - PIC16InstName[i_DEC].AddAddressMode(aAbsolute,$CE,3,3,''); - PIC16InstName[i_DEC].AddAddressMode(aAbsolutX,$DE,3,7,''); - PIC16InstName[i_DEX].name := 'DEX'; //Decrement Index X by One - PIC16InstName[i_DEX].AddAddressMode(aImplied_,$CA,1,2,''); - PIC16InstName[i_DEY].name := 'DEY'; //Decrement Index Y by One - PIC16InstName[i_DEY].AddAddressMode(aImplied_,$88,1,2,''); - PIC16InstName[i_EOR].name := 'EOR'; //Exclusive-OR Memory with Accumulator - PIC16InstName[i_EOR].AddAddressMode(aImmediat,$49,2,2,''); - PIC16InstName[i_EOR].AddAddressMode(aZeroPage,$45,2,3,''); - PIC16InstName[i_EOR].AddAddressMode(aZeroPagX,$55,2,4,''); - PIC16InstName[i_EOR].AddAddressMode(aAbsolute,$4D,3,4,''); - PIC16InstName[i_EOR].AddAddressMode(aAbsolutX,$5D,3,4,'*'); - PIC16InstName[i_EOR].AddAddressMode(aAbsolutY,$59,3,4,'*'); - PIC16InstName[i_EOR].AddAddressMode(aIdxIndir,$41,2,6,''); - PIC16InstName[i_EOR].AddAddressMode(aIndirIdx,$51,2,5,'*'); - PIC16InstName[i_INC].name := 'INC'; //Increment Memory by One - PIC16InstName[i_INC].AddAddressMode(aZeroPage,$E6,2,5,''); - PIC16InstName[i_INC].AddAddressMode(aZeroPagX,$F6,2,6,''); - PIC16InstName[i_INC].AddAddressMode(aAbsolute,$EE,3,6,''); - PIC16InstName[i_INC].AddAddressMode(aAbsolutX,$FE,3,7,''); - PIC16InstName[i_INX].name := 'INX'; //Increment Index X by One - PIC16InstName[i_INX].AddAddressMode(aImplied_,$E8,1,2,''); - PIC16InstName[i_INY].name := 'INY'; //Increment Index Y by One - PIC16InstName[i_INY].AddAddressMode(aImplied_,$C8,1,2,''); - PIC16InstName[i_JMP].name := 'JMP'; //Jump to New Location - PIC16InstName[i_JMP].AddAddressMode(aAbsolute,$4C,3,3,''); - PIC16InstName[i_JMP].AddAddressMode(aIndirect,$6C,3,5,''); - PIC16InstName[i_JSR].name := 'JSR'; //Jump to New Location Saving Return Address - PIC16InstName[i_JSR].AddAddressMode(aAbsolute,$20,3,6,''); - PIC16InstName[i_LDA].name := 'LDA'; //Load Accumulator with Memory - PIC16InstName[i_LDA].AddAddressMode(aImmediat,$A9,2,2,''); - PIC16InstName[i_LDA].AddAddressMode(aZeroPage,$A5,2,3,''); - PIC16InstName[i_LDA].AddAddressMode(aZeroPagX,$B5,2,4,''); - PIC16InstName[i_LDA].AddAddressMode(aAbsolute,$AD,3,4,''); - PIC16InstName[i_LDA].AddAddressMode(aAbsolutX,$BD,3,4,'*'); - PIC16InstName[i_LDA].AddAddressMode(aAbsolutY,$B9,3,4,'*'); - PIC16InstName[i_LDA].AddAddressMode(aIdxIndir,$A1,2,6,''); - PIC16InstName[i_LDA].AddAddressMode(aIndirIdx,$B1,2,5,'*'); - PIC16InstName[i_LDX].name := 'LDX'; //Load Index X with Memory - PIC16InstName[i_LDX].AddAddressMode(aImmediat,$A2,2,2,''); - PIC16InstName[i_LDX].AddAddressMode(aZeroPage,$A6,2,3,''); - PIC16InstName[i_LDX].AddAddressMode(aZeroPagY,$B6,2,4,''); - PIC16InstName[i_LDX].AddAddressMode(aAbsolute,$AE,3,4,''); - PIC16InstName[i_LDX].AddAddressMode(aAbsolutY,$BE,3,4,'*'); - PIC16InstName[i_LDY].name := 'LDY'; //Load Index Y with Memory - PIC16InstName[i_LDY].AddAddressMode(aImmediat,$A0,2,2,''); - PIC16InstName[i_LDY].AddAddressMode(aZeroPage,$A4,2,3,''); - PIC16InstName[i_LDY].AddAddressMode(aZeroPagX,$B4,2,4,''); - PIC16InstName[i_LDY].AddAddressMode(aAbsolute,$AC,3,4,''); - PIC16InstName[i_LDY].AddAddressMode(aAbsolutX,$BC,3,4,'*'); - PIC16InstName[i_LSR].name := 'LSR'; //Shift One Bit Right (Memory orAccumulator) - PIC16InstName[i_LSR].AddAddressMode(aAcumulat,$4A,1,2,''); - PIC16InstName[i_LSR].AddAddressMode(aZeroPage,$46,2,5,''); - PIC16InstName[i_LSR].AddAddressMode(aZeroPagX,$56,2,6,''); - PIC16InstName[i_LSR].AddAddressMode(aAbsolute,$4E,3,6,''); - PIC16InstName[i_LSR].AddAddressMode(aAbsolutX,$5E,3,7,''); - PIC16InstName[i_NOP].name := 'NOP'; //No Operation - PIC16InstName[i_NOP].AddAddressMode(aImplied_,$EA,1,2,''); - PIC16InstName[i_ORA].name := 'ORA'; //OR Memory with Accumulator - PIC16InstName[i_ORA].AddAddressMode(aImmediat,$09,2,2,''); - PIC16InstName[i_ORA].AddAddressMode(aZeroPage,$05,2,3,''); - PIC16InstName[i_ORA].AddAddressMode(aZeroPagX,$15,2,4,''); - PIC16InstName[i_ORA].AddAddressMode(aAbsolute,$0D,3,4,''); - PIC16InstName[i_ORA].AddAddressMode(aAbsolutX,$1D,3,4,'*'); - PIC16InstName[i_ORA].AddAddressMode(aAbsolutY,$19,3,4,'*'); - PIC16InstName[i_ORA].AddAddressMode(aIdxIndir,$01,2,6,''); - PIC16InstName[i_ORA].AddAddressMode(aIndirIdx,$11,2,5,'*'); - PIC16InstName[i_PHA].name := 'PHA'; //Push Accumulator on Stack - PIC16InstName[i_PHA].AddAddressMode(aImplied_,$48,1,3,''); - PIC16InstName[i_PHP].name := 'PHP'; //Push Processor Status on Stack - PIC16InstName[i_PHP].AddAddressMode(aImplied_,$08,1,3,''); - PIC16InstName[i_PLA].name := 'PLA'; //Pull Accumulator from Stack - PIC16InstName[i_PLA].AddAddressMode(aImplied_,$68,1,4,''); - PIC16InstName[i_PLP].name := 'PLP'; //Pull Processor Status fromStack - PIC16InstName[i_PLP].AddAddressMode(aImplied_,$28,1,4,''); - PIC16InstName[i_ROL].name := 'ROL'; //Rotate One Bit Left (Memory orAccumulator) - PIC16InstName[i_ROL].AddAddressMode(aAcumulat,$2A,1,2,''); - PIC16InstName[i_ROL].AddAddressMode(aZeroPage,$26,2,5,''); - PIC16InstName[i_ROL].AddAddressMode(aZeroPagX,$36,2,6,''); - PIC16InstName[i_ROL].AddAddressMode(aAbsolute,$2E,3,6,''); - PIC16InstName[i_ROL].AddAddressMode(aAbsolutX,$3E,3,7,''); - PIC16InstName[i_ROR].name := 'ROR'; //Rotate One Bit Right (Memory or Accumulator) - PIC16InstName[i_ROR].AddAddressMode(aAcumulat,$6A,1,2,''); - PIC16InstName[i_ROR].AddAddressMode(aZeroPage,$66,2,5,''); - PIC16InstName[i_ROR].AddAddressMode(aZeroPagX,$76,2,6,''); - PIC16InstName[i_ROR].AddAddressMode(aAbsolute,$6E,3,6,''); - PIC16InstName[i_ROR].AddAddressMode(aAbsolutX,$7E,3,7,''); - PIC16InstName[i_RTI].name := 'RTI'; //Return from Interrupt - PIC16InstName[i_RTI].AddAddressMode(aImplied_,$40,1,6,''); - PIC16InstName[i_RTS].name := 'RTS'; //Return from Subroutine - PIC16InstName[i_RTS].AddAddressMode(aImplied_,$60,1,6,''); - PIC16InstName[i_SBC].name := 'SBC'; //Subtract Memory from Accumulator withBorrow - PIC16InstName[i_SBC].AddAddressMode(aImmediat,$E9,2,2,''); - PIC16InstName[i_SBC].AddAddressMode(aZeroPage,$E5,2,3,''); - PIC16InstName[i_SBC].AddAddressMode(aZeroPagX,$F5,2,4,''); - PIC16InstName[i_SBC].AddAddressMode(aAbsolute,$ED,3,4,''); - PIC16InstName[i_SBC].AddAddressMode(aAbsolutX,$FD,3,4,'*'); - PIC16InstName[i_SBC].AddAddressMode(aAbsolutY,$F9,3,4,'*'); - PIC16InstName[i_SBC].AddAddressMode(aIdxIndir,$E1,2,6,''); - PIC16InstName[i_SBC].AddAddressMode(aIndirIdx,$F1,2,5,'*'); - PIC16InstName[i_SEC].name := 'SEC'; //Set Carry Flag - PIC16InstName[i_SEC].AddAddressMode(aImplied_,$38,1,2,''); - PIC16InstName[i_SED].name := 'SED'; //Set Decimal Flag - PIC16InstName[i_SED].AddAddressMode(aImplied_,$F8,1,2,''); - PIC16InstName[i_SEI].name := 'SEI'; //Set Interrupt Disable Status - PIC16InstName[i_SEI].AddAddressMode(aImplied_,$78,1,2,''); - PIC16InstName[i_STA].name := 'STA'; //Store Accumulator in Memory - PIC16InstName[i_STA].AddAddressMode(aZeroPage,$85,2,3,''); - PIC16InstName[i_STA].AddAddressMode(aZeroPagX,$95,2,4,''); - PIC16InstName[i_STA].AddAddressMode(aAbsolute,$8D,3,4,''); - PIC16InstName[i_STA].AddAddressMode(aAbsolutX,$9D,3,5,''); - PIC16InstName[i_STA].AddAddressMode(aAbsolutY,$99,3,5,''); - PIC16InstName[i_STA].AddAddressMode(aIdxIndir,$81,2,6,''); - PIC16InstName[i_STA].AddAddressMode(aIndirIdx,$91,2,6,''); - PIC16InstName[i_STX].name := 'STX'; //Store Index X in Memory - PIC16InstName[i_STX].AddAddressMode(aZeroPage,$86,2,3,''); - PIC16InstName[i_STX].AddAddressMode(aZeroPagY,$96,2,4,''); - PIC16InstName[i_STX].AddAddressMode(aAbsolute,$8E,3,4,''); - PIC16InstName[i_STY].name := 'STY'; //Sore Index Y in Memory - PIC16InstName[i_STY].AddAddressMode(aZeroPage,$84,2,3,''); - PIC16InstName[i_STY].AddAddressMode(aZeroPagX,$94,2,4,''); - PIC16InstName[i_STY].AddAddressMode(aAbsolute,$8C,3,4,''); - PIC16InstName[i_TAX].name := 'TAX'; //Transfer Accumulator to IndexX - PIC16InstName[i_TAX].AddAddressMode(aImplied_,$AA,1,2,''); - PIC16InstName[i_TAY].name := 'TAY'; //Transfer Accumulator to IndexY - PIC16InstName[i_TAY].AddAddressMode(aImplied_,$A8,1,2,''); - PIC16InstName[i_TSX].name := 'TSX'; //Transfer Stack Pointer toIndex X - PIC16InstName[i_TSX].AddAddressMode(aImplied_,$BA,1,2,''); - PIC16InstName[i_TXA].name := 'TXA'; //Transfer Index X to Accumulator - PIC16InstName[i_TXA].AddAddressMode(aImplied_,$8A,1,2,''); - PIC16InstName[i_TXS].name := 'TXS'; //Transfer Index X to StackRegister - PIC16InstName[i_TXS].AddAddressMode(aImplied_,$9A,1,2,''); - PIC16InstName[i_TYA].name := 'TYA'; //Transfer Index Y to Accumulator - PIC16InstName[i_TYA].AddAddressMode(aImplied_,$98,1,2,''); - - PIC16InstName[i_Inval].name := 'Inval'; - - -end; -initialization - InitTables; -end.