From 43d5e32e589f21210ce526e51f06650c42ca9397 Mon Sep 17 00:00:00 2001 From: Bill Chatfield Date: Sun, 18 Nov 2018 15:39:24 -0500 Subject: [PATCH] Added source coded from the Merlin32_v1.0.zip archive. --- Library/Ace.Macs.s | 62 + Library/Adb.Macs.s | 91 + Library/Anim.s | 83 + Library/Ctl.Macs.s | 305 +++ Library/Desk.Macs.s | 143 ++ Library/Dialog.Macs.s | 285 +++ Library/Dos.16.Macs.s | 177 ++ Library/Dos.8.Macs.s | 142 + Library/Event.Macs.s | 144 ++ Library/Female.Macs.s | 26 + Library/Font.Macs.s | 142 + Library/GsOs.Macs.s | 39 + Library/Int.Macs.s | 221 ++ Library/Line.Macs.s | 183 ++ Library/List.Macs.s | 111 + Library/Load.Macs.s | 113 + Library/Locator.Macs.s | 135 + Library/Logo.Macs.s | 87 + Library/Macros.s | 571 +++++ Library/Male.Macs.s | 26 + Library/Media.Macs.s | 137 + Library/Mem.Macs.s | 179 ++ Library/Menu.Macs.s | 372 +++ Library/Midi.Macs.s | 79 + Library/MidiSyn.Macs.s | 119 + Library/Misc.Macs.s | 278 ++ Library/NoteSeq.Macs.s | 89 + Library/NoteSyn.Macs.s | 66 + Library/Print.Macs.s | 220 ++ Library/Qd.Macs.s | 1102 ++++++++ Library/QdAux.Macs.s | 86 + Library/Resource.Macs.s | 229 ++ Library/Sane.Macs.s | 604 +++++ Library/Sch.Macs.s | 38 + Library/Scrap.Macs.s | 86 + Library/Sound.Macs.s | 111 + Library/Speech.Macs.s | 47 + Library/Std.Macs.s | 108 + Library/Text.Macs.s | 184 ++ Library/TextEdit.Macs.s | 199 ++ Library/Tool219.Macs.s | 86 + Library/Tool220.Macs.s | 34 + Library/Util.Macs.s | 796 ++++++ Library/VGA.Macs.s | 66 + Library/Video.Macs.s | 89 + Library/Window.Macs.s | 537 ++++ Source/Dc_Library.c | 5397 +++++++++++++++++++++++++++++++++++++++ Source/Dc_Library.h | 275 ++ Source/Main.c | 154 ++ Source/Merlin32 | Bin 0 -> 238168 bytes Source/a65816_Code.c | 2912 +++++++++++++++++++++ Source/a65816_Code.h | 13 + Source/a65816_Cond.c | 219 ++ Source/a65816_Cond.h | 11 + Source/a65816_Data.c | 717 ++++++ Source/a65816_Data.h | 12 + Source/a65816_File.c | 885 +++++++ Source/a65816_File.h | 35 + Source/a65816_Line.c | 3324 ++++++++++++++++++++++++ Source/a65816_Line.h | 219 ++ Source/a65816_Link.c | 1165 +++++++++ Source/a65816_Link.h | 11 + Source/a65816_Lup.c | 528 ++++ Source/a65816_Lup.h | 11 + Source/a65816_Macro.c | 962 +++++++ Source/a65816_Macro.h | 42 + Source/a65816_OMF.c | 1597 ++++++++++++ Source/a65816_OMF.h | 177 ++ Source/linux_makefile | 14 + 69 files changed, 27707 insertions(+) create mode 100644 Library/Ace.Macs.s create mode 100644 Library/Adb.Macs.s create mode 100644 Library/Anim.s create mode 100644 Library/Ctl.Macs.s create mode 100644 Library/Desk.Macs.s create mode 100644 Library/Dialog.Macs.s create mode 100644 Library/Dos.16.Macs.s create mode 100644 Library/Dos.8.Macs.s create mode 100644 Library/Event.Macs.s create mode 100644 Library/Female.Macs.s create mode 100644 Library/Font.Macs.s create mode 100644 Library/GsOs.Macs.s create mode 100644 Library/Int.Macs.s create mode 100644 Library/Line.Macs.s create mode 100644 Library/List.Macs.s create mode 100644 Library/Load.Macs.s create mode 100644 Library/Locator.Macs.s create mode 100644 Library/Logo.Macs.s create mode 100644 Library/Macros.s create mode 100644 Library/Male.Macs.s create mode 100644 Library/Media.Macs.s create mode 100644 Library/Mem.Macs.s create mode 100644 Library/Menu.Macs.s create mode 100644 Library/Midi.Macs.s create mode 100644 Library/MidiSyn.Macs.s create mode 100644 Library/Misc.Macs.s create mode 100644 Library/NoteSeq.Macs.s create mode 100644 Library/NoteSyn.Macs.s create mode 100644 Library/Print.Macs.s create mode 100644 Library/Qd.Macs.s create mode 100644 Library/QdAux.Macs.s create mode 100644 Library/Resource.Macs.s create mode 100644 Library/Sane.Macs.s create mode 100644 Library/Sch.Macs.s create mode 100644 Library/Scrap.Macs.s create mode 100644 Library/Sound.Macs.s create mode 100644 Library/Speech.Macs.s create mode 100644 Library/Std.Macs.s create mode 100644 Library/Text.Macs.s create mode 100644 Library/TextEdit.Macs.s create mode 100644 Library/Tool219.Macs.s create mode 100644 Library/Tool220.Macs.s create mode 100644 Library/Util.Macs.s create mode 100644 Library/VGA.Macs.s create mode 100644 Library/Video.Macs.s create mode 100644 Library/Window.Macs.s create mode 100644 Source/Dc_Library.c create mode 100644 Source/Dc_Library.h create mode 100644 Source/Main.c create mode 100755 Source/Merlin32 create mode 100644 Source/a65816_Code.c create mode 100644 Source/a65816_Code.h create mode 100644 Source/a65816_Cond.c create mode 100644 Source/a65816_Cond.h create mode 100644 Source/a65816_Data.c create mode 100644 Source/a65816_Data.h create mode 100644 Source/a65816_File.c create mode 100644 Source/a65816_File.h create mode 100644 Source/a65816_Line.c create mode 100644 Source/a65816_Line.h create mode 100644 Source/a65816_Link.c create mode 100644 Source/a65816_Link.h create mode 100644 Source/a65816_Lup.c create mode 100644 Source/a65816_Lup.h create mode 100644 Source/a65816_Macro.c create mode 100644 Source/a65816_Macro.h create mode 100644 Source/a65816_OMF.c create mode 100644 Source/a65816_OMF.h create mode 100644 Source/linux_makefile diff --git a/Library/Ace.Macs.s b/Library/Ace.Macs.s new file mode 100644 index 0000000..ab50ebc --- /dev/null +++ b/Library/Ace.Macs.s @@ -0,0 +1,62 @@ +* ACE tool macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; + +_ACEBootInit MAC + Tool $11D + <<< +~ACEStartUp MAC + PHW ]1 +_ACEStartUp MAC + Tool $21D + <<< +_ACEShutDown MAC + Tool $31D + <<< +~ACEVersion MAC + PHA +_ACEVersion MAC + Tool $41D + <<< +_ACEReset MAC + Tool $51D + <<< +~ACEStatus MAC + PHA +_ACEStatus MAC + Tool $61D + <<< +~ACEInfo MAC + P2SW ]1 +_ACEInfo MAC + Tool $71D + <<< +~ACECompress MAC + PxL ]1;]2;]3;]4 + PxW ]5;]6 +_ACECompress MAC + Tool $91D + <<< +~ACEExpand MAC + PxL ]1;]2;]3;]4 + PxW ]5;]6 +_ACEExpand MAC + Tool $A1D + <<< +_ACECompBegin MAC + Tool $B1D + <<< +_ACEExpBegin MAC + Tool $C1D + <<< +_GetACEExpState MAC + Tool $D1D + <<< +_SetACEExpState MAC + Tool $E1D + <<< + diff --git a/Library/Adb.Macs.s b/Library/Adb.Macs.s new file mode 100644 index 0000000..5879799 --- /dev/null +++ b/Library/Adb.Macs.s @@ -0,0 +1,91 @@ +* Desktop Bus tool macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_ADBBootInit MAC + Tool $109 + <<< +_ADBStartUp MAC + Tool $209 + <<< +_ADBShutDown MAC + Tool $309 + <<< +_ADBVersion MAC + Tool $409 + <<< +_ADBReset MAC + Tool $509 + <<< +~ADBStatus MAC + PHA +_ADBStatus MAC + Tool $609 + <<< +~SendInfo MAC + PHW ]1 + PHLW ]2;]3 +_SendInfo MAC + Tool $909 + <<< +~ReadKeyMicroData MAC + PHW ]1 + PHLW ]2;]3 +_ReadKeyMicroData MAC + Tool $A09 + <<< +~ReadKeyMicroMem MAC + PxL ]1;]2 + PHW ]3 +_ReadKeyMicroMem MAC + Tool $B09 + <<< +~AsyncADBReceive MAC + PHLW ]1;]2 +_AsyncADBReceive MAC + Tool $D09 + <<< +~SyncADBReceive MAC + PHW ]1 + PHLW ]2;]3 +_SyncADBReceive MAC + Tool $E09 + <<< +_AbsOn MAC + Tool $F09 + <<< +_AbsOff MAC + Tool $1009 + <<< +~ReadAbs MAC + PHA +_ReadAbs MAC + Tool $1109 + <<< +~GetAbsScale MAC + PHL ]1 +_GetAbsScale MAC + Tool $1209 + <<< +~SetAbsScale MAC + PHL ]1 +_SetAbsScale MAC + Tool $1309 + <<< +~SRQPoll MAC + PHLW ]1;]2 +_SRQPoll MAC + Tool $1409 + <<< +~SRQRemove MAC + PHW ]1 +_SRQRemove MAC + Tool $1509 + <<< +_ClearSRQTable MAC + Tool $1609 + <<< + diff --git a/Library/Anim.s b/Library/Anim.s new file mode 100644 index 0000000..30de65a --- /dev/null +++ b/Library/Anim.s @@ -0,0 +1,83 @@ +* +* Anim Tool Set +* + +_AnimBootInit MAC + Tool $0125 + <<< +_AnimStartUp MAC + Tool $0225 + <<< +_AnimShutDown MAC + Tool $0325 + <<< +_AnimVersion MAC + Tool $0425 + <<< +_AnimReset MAC + Tool $0525 + <<< +_AnimStatus MAC + Tool $0623 + <<< +_AnimIdleDebug MAC + Tool $0825 + <<< +_StartScene MAC + Tool $0925 + <<< +_StopScene MAC + Tool $0A25 + <<< +_StartFrameTimer MAC + Tool $0B25 + <<< +_StopFrameTimer MAC + Tool $0C25 + <<< +_SetBackGndPort MAC + Tool $0D25 + <<< +_RefreshBack MAC + Tool $0E25 + <<< +_StartChar MAC + Tool $0F25 + <<< +_MoveChar MAC + Tool $1025 + <<< +_GetCharRecPtr MAC + Tool $1125 + <<< +_KillChar MAC + Tool $1225 + <<< +_LoadActor MAC + Tool $1325 + <<< +_SetCharScript MAC + Tool $1425 + <<< +_RunAnimScripts MAC + Tool $1525 + <<< +_FillAddrTable MAC + Tool $1625 + <<< +_CompileRect MAC + Tool $1725 + <<< +_StartTockTask MAC + Tool $1825 + <<< +_FireTockTask MAC + Tool $1925 + <<< +_SetForeGndPort MAC + Tool $1A25 + <<< +_SetAnimWindow MAC + Tool $1B25 + <<< + diff --git a/Library/Ctl.Macs.s b/Library/Ctl.Macs.s new file mode 100644 index 0000000..40e45ea --- /dev/null +++ b/Library/Ctl.Macs.s @@ -0,0 +1,305 @@ +* Control Manager macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_CtlBootInit MAC + Tool $110 + <<< +~CtlStartUp MAC + PxW ]1;]2 +_CtlStartUp MAC +_InitCtrlMgr MAC + Tool $210 + <<< +_CtlShutDown MAC +_CtrlShutDown MAC + Tool $310 + <<< +~CtlVersion MAC + PHA +_CtlVersion MAC + Tool $410 + <<< +_CtlReset MAC + Tool $510 + <<< +~CtlStatus MAC + PHA +_CtlStatus MAC + Tool $610 + <<< +_NewControl MAC + Tool $910 + <<< +~DisposeControl MAC + PHL ]1 +_DisposeControl MAC + Tool $A10 + <<< +~KillControls MAC + PHL ]1 +_KillControls MAC + Tool $B10 + <<< +~SetCtlTitle MAC + PxL ]1;]2 +_SetCtlTitle MAC + Tool $C10 + <<< +~GetCtlTitle MAC + P2SL ]1 +_GetCtlTitle MAC + Tool $D10 + <<< +~HideControl MAC + PHL ]1 +_HideControl MAC + Tool $E10 + <<< +~ShowControl MAC + PHL ]1 +_ShowControl MAC + Tool $F10 + <<< +~DrawControls MAC + PHL ]1 +_DrawControls MAC + Tool $1010 + <<< +~HiliteControl MAC + PHWL ]1;]2 +_HiliteControl MAC + Tool $1110 + <<< +_CtlNewRes MAC + Tool $1210 + <<< +~FindControl MAC + PHA + PHLW ]1;]2 + PHWL ]3;]4 +_FindControl MAC + Tool $1310 + <<< +~TestControl MAC + P1SW ]1 + PHWL ]2;]3 +_TestControl MAC + Tool $1410 + <<< +~TrackControl MAC + PHA + PxW ]1;]2 + PxL ]3;]4 +_TrackControl MAC + Tool $1510 + <<< +~MoveControl MAC + PxW ]1;]2 + PHL ]3 +_MoveControl MAC + Tool $1610 + <<< +~DragControl MAC + PxW ]1;]2 + PxL ]3;]4 + PHWL ]5;]6 +_DragControl MAC + Tool $1710 + <<< +~SetCtlIcons MAC + P2SL ]1 +_SetCtlIcons MAC + Tool $1810 + <<< +~SetCtlValue MAC + PHWL ]1;]2 +_SetCtlValue MAC + Tool $1910 + <<< +~GetCtlValue MAC + P1SL ]1 +_GetCtlValue MAC + Tool $1A10 + <<< +~SetCtlParams MAC + PxW ]1;]2 + PHL ]3 +_SetCtlParams MAC + Tool $1B10 + <<< +~GetCtlParams MAC + P2SL ]1 +_GetCtlParams MAC + Tool $1C10 + <<< +~DragRect MAC + P2SL ]1 + PHLW ]2;]3 + PHWL ]4;]5 + PxL ]6;]7 + PHW ]8 +_DragRect MAC + Tool $1D10 + <<< +~GrowSize MAC + PHS 2 +_GrowSize MAC + Tool $1E10 + <<< +~GetCtlDpage MAC + PHA +_GetCtlDpage MAC + Tool $1F10 + <<< +~SetCtlAction MAC + PxL ]1;]2 +_SetCtlAction MAC + Tool $2010 + <<< +~GetCtlAction MAC + P2SL ]1 +_GetCtlAction MAC + Tool $2110 + <<< +~SetCtlRefCon MAC + PxL ]1;]2 +_SetCtlRefCon MAC + Tool $2210 + <<< +~GetCtlRefCon MAC + P2SL ]1 +_GetCtlRefCon MAC + Tool $2310 + <<< +~EraseControl MAC + PHL ]1 +_EraseControl MAC + Tool $2410 + <<< +~DrawOneCtl MAC + PHL ]1 +_DrawOneCtl MAC + Tool $2510 + <<< +~FindTargetCtl MAC + PHS 2 +_FindTargetCtl MAC + Tool $2610 + <<< +~MakeNextCtlTarget MAC + PHS 2 +_MakeNextCtlTarget MAC + Tool $2710 + <<< +~MakeThisCtlTarget MAC + PHL ]1 +_MakeThisCtlTarget MAC + Tool $2810 + <<< +~SendEventToCtl MAC + P1SW ]1 + PxL ]2;]3 +_SendEventToCtl MAC + Tool $2910 + <<< +~GetCtlID MAC + P2SL ]1 +_GetCtlID MAC + Tool $2A10 + <<< +~SetCtlID MAC + PxL ]1;]2 +_SetCtlID MAC + Tool $2B10 + <<< +~CallCtlDefProc MAC + PHLW ]1;]2 + PHL ]3 +_CallCtlDefProc MAC + Tool $2C10 + <<< +~NotifyCtls MAC + PxW ]1;]2 + PxL ]3;]4 +_NotifyCtls MAC + Tool $2D10 + <<< +~GetCtlMoreFlags MAC + P1SL ]1 +_GetCtlMoreFlags MAC + Tool $2E10 + <<< +~SetCtlMoreFlags MAC + PHWL ]1;]2 +_SetCtlMoreFlags MAC + Tool $2F10 + <<< +~GetCtlHandleFromID MAC + PHS 2 + PxL ]1;]2 +_GetCtlHandleFromID MAC + Tool $3010 + <<< +~NewControl2 MAC + P2SL ]1 + PHWL ]2;]3 +_NewControl2 MAC + Tool $3110 + <<< +~CMLoadResource MAC + P2SW ]1 + PHL ]2 +_CMLoadResource MAC + Tool $3210 + <<< +~CMReleaseResource MAC + PHWL ]1;]2 +_CMReleaseResource MAC + Tool $3310 + <<< +~SetCtlParamPtr MAC + PHL ]1 +_SetCtlParamPtr MAC + Tool $3410 + <<< +~GetCtlParamPtr MAC + PHS 2 +_GetCtlParamPtr MAC + Tool $3510 + <<< +~InvalCtls MAC + PHL ]1 +_InvalCtls MAC + Tool $3710 + <<< +~qCtlStartUp MAC + PHW ]1 + NextDP ]2;$100 + Tool $210 + <<< +_FindRadioButton MAC + Tool $3910 + <<< +_SetLETextByID MAC + Tool $3A10 + <<< +_GetLETextByID MAC + Tool $3B10 + <<< +_SetCtlValueByID MAC + Tool $3C10 + <<< +_GetCtlValueByID MAC + Tool $3D10 + <<< +_InvalOneCtlByID MAC + Tool $3E10 + <<< +_HiliteCtlByID MAC + Tool $3F10 + <<< + diff --git a/Library/Desk.Macs.s b/Library/Desk.Macs.s new file mode 100644 index 0000000..c5442ed --- /dev/null +++ b/Library/Desk.Macs.s @@ -0,0 +1,143 @@ +* Desk Manager macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_DeskBootInit MAC + Tool $105 + <<< +_DeskStartUp MAC + Tool $205 + <<< +_DeskShutDown MAC + Tool $305 + <<< +~DeskVersion MAC + PHA +_DeskVersion MAC + Tool $405 + <<< +_DeskReset MAC + Tool $505 + <<< +~DeskStatus MAC + PHA +_DeskStatus MAC + Tool $605 + <<< +_SaveScrn MAC + Tool $905 + <<< +_RestScrn MAC + Tool $A05 + <<< +_SaveAll MAC + Tool $B05 + <<< +_RestAll MAC + Tool $C05 + <<< +~InstallNDA MAC + PHL ]1 +_InstallNDA MAC + Tool $E05 + <<< +~InstallCDA MAC + PHL ]1 +_InstallCDA MAC + Tool $F05 + <<< +_ChooseCDA MAC + Tool $1105 + <<< +~SetDAStrPtr MAC + PxL ]1;]2 +_SetDAStrPtr MAC + Tool $1305 + <<< +~GetDAStrPtr MAC + PHS 2 +_GetDAStrPtr MAC + Tool $1405 + <<< +~OpenNDA MAC + P1SW ]1 +_OpenNDA MAC + Tool $1505 + <<< +~CloseNDA MAC + PHW ]1 +_CloseNDA MAC + Tool $1605 + <<< +~SystemClick MAC + PxL ]1;]2 + PHW ]3 +_SystemClick MAC + Tool $1705 + <<< +~SystemEdit MAC + P1SW ]1 +_SystemEdit MAC + Tool $1805 + <<< +_SystemTask MAC + Tool $1905 + <<< +~SystemEvent MAC + P1SW ]1 + PxL ]2;]3;]4 + PHW ]5 +_SystemEvent MAC + Tool $1A05 + <<< +~GetNumNDAs MAC + PHA +_GetNumNDAs MAC + Tool $1B05 + <<< +~CloseNDAbyWinPtr MAC + PHL ]1 +_CloseNDAbyWinPtr MAC + Tool $1C05 + <<< +_CloseAllNDAs MAC + Tool $1D05 + <<< +~FixAppleMenu MAC + PHW ]1 +_FixAppleMenu MAC + Tool $1E05 + <<< +~AddToRunQ MAC + PHL ]1 +_AddToRunQ MAC + Tool $1F05 + <<< +~RemoveFromRunQ MAC + PHL ]1 +_RemoveFromRunQ MAC + Tool $2005 + <<< +~RemoveCDA MAC + PHL ]1 +_RemoveCDA MAC + Tool $2105 + <<< +~RemoveNDA MAC + PHL ]1 +_RemoveNDA MAC + Tool $2205 + <<< +_GetDeskAccInfo MAC + Tool $2305 + <<< +_CallDeskAcc MAC + Tool $2405 + <<< +_GetDeskGlobal MAC + Tool $2505 + <<< + diff --git a/Library/Dialog.Macs.s b/Library/Dialog.Macs.s new file mode 100644 index 0000000..fccdd06 --- /dev/null +++ b/Library/Dialog.Macs.s @@ -0,0 +1,285 @@ +* Dialog Manager macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_DialogBootInit MAC + Tool $115 + <<< +~DialogStartUp MAC + PHW ]1 +_DialogStartUp MAC + Tool $215 + <<< +_DialogShutDown MAC + Tool $315 + <<< +~DialogVersion MAC + PHA +_DialogVersion MAC + Tool $415 + <<< +_DialogReset MAC + Tool $515 + <<< +~DialogStatus MAC + PHA +_DialogStatus MAC + Tool $615 + <<< +~ErrorSound MAC + PHL ]1 +_ErrorSound MAC + Tool $915 + <<< +~NewModalDialog MAC + P2SL ]1 + PHWL ]2;]3 +_NewModalDialog MAC + Tool $A15 + <<< +~NewModelessDialog MAC + P2SL ]1 + PxL ]2;]3 + PHWL ]4;]5 + PHL ]6 +_NewModelessDialog MAC + Tool $B15 + <<< +~CloseDialog MAC + PHL ]1 +_CloseDialog MAC + Tool $C15 + <<< +~NewDItem MAC + PHLW ]1;]2 + PHLW ]3;]4 + PHLW ]5;]6 + PHWL ]7;]8 +_NewDItem MAC + Tool $D15 + <<< +~RemoveDItem MAC + PHLW ]1;]2 +_RemoveDItem MAC + Tool $E15 + <<< +~ModalDialog MAC + P1SL ]1 +_ModalDialog MAC + Tool $F15 + <<< +~IsDialogEvent MAC + P1SL ]1 +_IsDialogEvent MAC + Tool $1015 + <<< +~DialogSelect MAC + P1SL ]1 + PxL ]2;]3 +_DialogSelect MAC + Tool $1115 + <<< +~DlgCut MAC + PHL ]1 +_DlgCut MAC + Tool $1215 + <<< +~DlgCopy MAC + PHL ]1 +_DlgCopy MAC + Tool $1315 + <<< +~DlgPaste MAC + PHL ]1 +_DlgPaste MAC + Tool $1415 + <<< +~DlgDelete MAC + PHL ]1 +_DlgDelete MAC + Tool $1515 + <<< +~DrawDialog MAC + PHL ]1 +_DrawDialog MAC + Tool $1615 + <<< +~Alert MAC + PHA + PxL ]1;]2 +_Alert MAC + Tool $1715 + <<< +~StopAlert MAC + PHA + PxL ]1;]2 +_StopAlert MAC + Tool $1815 + <<< +~NoteAlert MAC + PHA + PxL ]1;]2 +_NoteAlert MAC + Tool $1915 + <<< +~CautionAlert MAC + PHA + PxL ]1;]2 +_CautionAlert MAC + Tool $1A15 + <<< +~ParamText MAC + PxL ]1;]2;]3;]4 +_ParamText MAC + Tool $1B15 + <<< +~SetDAFont MAC + PHL ]1 +_SetDAFont MAC + Tool $1C15 + <<< +~GetControlDItem MAC + PHS 2 + PHLW ]1;]2 +_GetControlDItem MAC + Tool $1E15 + <<< +~GetIText MAC + PHL ]1 + PHWL ]2;]3 +_GetIText MAC + Tool $1F15 + <<< +~SetIText MAC + PHL ]1 + PHWL ]2;]3 +_SetIText MAC + Tool $2015 + <<< +~SelectIText MAC + PHL ]1 + PxW ]2;]3;]4 +_SelectIText MAC + Tool $2115 + <<< +~HideDItem MAC + PHLW ]1;]2 +_HideDItem MAC + Tool $2215 + <<< +~ShowDItem MAC + PHLW ]1;]2 +_ShowDItem MAC + Tool $2315 + <<< +~FindDItem MAC + PHA + PxL ]1;]2 +_FindDItem MAC + Tool $2415 + <<< +~UpdateDialog MAC + PxL ]1;]2 +_UpdateDialog MAC + Tool $2515 + <<< +~GetDItemType MAC + PHA + PHLW ]1;]2 +_GetDItemType MAC + Tool $2615 + <<< +~SetDItemType MAC + PHW ]1 + PHLW ]2;]3 +_SetDItemType MAC + Tool $2715 + <<< +~GetDItemBox MAC + PHL ]1 + PHWL ]2;]3 +_GetDItemBox MAC + Tool $2815 + <<< +~SetDItemBox MAC + PHL ]1 + PHWL ]2;]3 +_SetDItemBox MAC + Tool $2915 + <<< +~GetFirstDItem MAC + P1SL ]1 +_GetFirstDItem MAC + Tool $2A15 + <<< +~GetNextDItem MAC + PHA + PHLW ]1;]2 +_GetNextDItem MAC + Tool $2B15 + <<< +~ModalDialog2 MAC + P2SL ]1 +_ModalDialog2 MAC + Tool $2C15 + <<< +~GetDItemValue MAC + PHA + PHLW ]1;]2 +_GetDItemValue MAC + Tool $2E15 + <<< +~SetDItemValue MAC + PHW ]1 + PHLW ]2;]3 +_SetDItemValue MAC + Tool $2F15 + <<< +~GetNewModalDialog MAC + P2SL ]1 +_GetNewModalDialog MAC + Tool $3215 + <<< +~GetNewDItem MAC + PxL ]1;]2 +_GetNewDItem MAC + Tool $3315 + <<< +~GetAlertStage MAC + PHA +_GetAlertStage MAC + Tool $3415 + <<< +_ResetAlertStage MAC + Tool $3515 + <<< +~DefaultFilter MAC + PHA + PxL ]1;]2;]3 +_DefaultFilter MAC + Tool $3615 + <<< +~GetDefButton MAC + P1SL ]1 +_GetDefButton MAC + Tool $3715 + <<< +~SetDefButton MAC + PHWL ]1;]2 +_SetDefButton MAC + Tool $3815 + <<< +~DisableDItem MAC + PHLW ]1;]2 +_DisableDItem MAC + Tool $3915 + <<< +~EnableDItem MAC + PHLW ]1;]2 +_EnableDItem MAC + Tool $3A15 + <<< + diff --git a/Library/Dos.16.Macs.s b/Library/Dos.16.Macs.s new file mode 100644 index 0000000..d97f965 --- /dev/null +++ b/Library/Dos.16.Macs.s @@ -0,0 +1,177 @@ +*=============================== +* ProDOS-16 macro and equates +* +* Use with syntax: +* +* _CMDNAME PARMADR +* +* where "CMDNAME" is one of the +* following labels and "PARMADR" +* is the label of the parameters +* table to use. +* +*------------------------------- + +; +; Copyright Apple Computer, Inc. 1986, 1987 +; All Rights Reserved +; +open = $10 +read = $12 +write = $13 +close = $14 + +_CREATE MAC + DOS16 $01;]1 + <<< + +_DESTROY MAC + DOS16 $02;]1 + <<< + +_CHANGE_PATH MAC + DOS16 $04;]1 + <<< + +_SET_FILE_INFO MAC + DOS16 $05;]1 + <<< + +_GET_FILE_INFO MAC + DOS16 $06;]1 + <<< + +_VOLUME MAC + DOS16 $08;]1 + <<< + +_SET_PREFIX MAC + DOS16 $09;]1 + <<< + +_SETPREFIX MAC ; alternate name + DOS16 $09;]1 + <<< + +_GET_PREFIX MAC + DOS16 $0A;]1 + <<< + +_GETPREFIX MAC ; alternate name + DOS16 $0A;]1 + <<< + +_CLEAR_BACKUP_BIT MAC + DOS16 $0B;]1 + <<< + +_OPEN MAC + DOS16 $10;]1 + <<< + +_NEWLINE MAC + DOS16 $11;]1 + <<< + +_READ MAC + DOS16 $12;]1 + <<< + +_WRITE MAC + DOS16 $13;]1 + <<< + +_CLOSE MAC + DOS16 $14;]1 + <<< + +_FLUSH MAC + DOS16 $15;]1 + <<< + +_SET_MARK MAC + DOS16 $16;]1 + <<< + +_GET_MARK MAC + DOS16 $17;]1 + <<< + +_SET_EOF MAC + DOS16 $18;]1 + <<< + +_GET_EOF MAC + DOS16 $19;]1 + <<< + +_SET_LEVEL MAC + DOS16 $1A;]1 + <<< + +_GET_LEVEL MAC + DOS16 $1B;]1 + <<< + +_GET_DIR_ENTRY MAC + DOS16 $1C;]1 + <<< + +_GET_DEV_NUM MAC + DOS16 $20;]1 + <<< + +_GET_LAST_DEV MAC + DOS16 $21;]1 + <<< + +_READ_BLOCK MAC + DOS16 $22;]1 + <<< + +_WRITE_BLOCK MAC + DOS16 $23;]1 + <<< + +_FORMAT MAC + DOS16 $24;]1 + <<< + +_ERASE_DISK MAC + DOS16 $25;]1 + <<< + +_GET_NAME MAC + DOS16 $27;]1 + <<< + +_GET_BOOT_VOL MAC + DOS16 $28;]1 + <<< + +_QUIT MAC + DOS16 $29;]1 + <<< + +_GET_VERSION MAC + DOS16 $2A;]1 + <<< + +_D_INFO MAC + DOS16 $2C;]1 + <<< + +_ALLOC_INTERRUPT MAC + DOS16 $31;]1 + <<< + +_DEALLOC_INTERRUPT MAC + DOS16 $32;]1 + <<< + +DOS16 MAC + JSL $E100A8 + DA ]1 ; Change to ]1.$2000 for Class 1 P16 calls. + ADRL ]2 + <<< + diff --git a/Library/Dos.8.Macs.s b/Library/Dos.8.Macs.s new file mode 100644 index 0000000..06f72f9 --- /dev/null +++ b/Library/Dos.8.Macs.s @@ -0,0 +1,142 @@ +*=============================== +* ProDOS-8 macro and equates +* +* Use with syntax: +* +* command PARMADR +* +* where "command" is one of the +* following labels and "PARMADR" +* is the label of the parameters +* table to use. +* +*------------------------------- + +; +; Copyright Apple Computer, Inc. 1986, 1987 +; All Rights Reserved +; +* MLI call codes: + +ALLOC_INTERRUPT MAC + DOS8 $40;]1 + <<< + +DEALLOC_INTERRUPT MAC + DOS8 $41;]1 + <<< + +APPLE_TALK MAC + DOS8 $42;]1 + <<< + +SPECIAL_OPEN_FORK MAC + DOS8 $43;]1 + <<< + +BYTE_RANGE_LOCK MAC + DOS8 $44;]1 + <<< + +QUIT MAC + DOS8 $65;]1 + <<< + +READ_BLOCK MAC + DOS8 $80;]1 + <<< + +WRITE_BLOCK MAC + DOS8 $81;]1 + <<< + +GET_TIME MAC + DOS8 $82;]1 + <<< + +CREATE MAC + DOS8 $C0;]1 + <<< + +DESTROY MAC + DOS8 $C1;]1 + <<< + +RENAME MAC + DOS8 $C2;]1 + <<< + +SET_FILE_INFO MAC + DOS8 $C3;]1 + <<< + +GET_FILE_INFO MAC + DOS8 $C4;]1 + <<< + +ON_LINE MAC + DOS8 $C5;]1 + <<< + +SET_PREFIX MAC + DOS8 $C6;]1 + <<< + +GET_PREFIX MAC + DOS8 $C7;]1 + <<< + +OPEN MAC + DOS8 $C8;]1 + <<< + +NEWLINE MAC + DOS8 $C9;]1 + <<< + +READ MAC + DOS8 $CA;]1 + <<< + +WRITE MAC + DOS8 $CB;]1 + <<< + +CLOSE MAC + DOS8 $CC;]1 + <<< + +FLUSH MAC + DOS8 $CD;]1 + <<< + +SET_MARK MAC + DOS8 $CE;]1 + <<< + +GET_MARK MAC + DOS8 $CF;]1 + <<< + +SET_EOF MAC + DOS8 $D0;]1 + <<< + +GET_EOF MAC + DOS8 $D1;]1 + <<< + +SET_BUF MAC + DOS8 $D2;]1 + <<< + +GET_BUF MAC + DOS8 $D3;]1 + <<< + +DOS8 MAC + JSR $BF00 + DFB ]1 + DA ]2 + <<< + diff --git a/Library/Event.Macs.s b/Library/Event.Macs.s new file mode 100644 index 0000000..9ca846b --- /dev/null +++ b/Library/Event.Macs.s @@ -0,0 +1,144 @@ +* Event Manager macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_EMBootInit MAC + Tool $106 + <<< +~EMStartUp MAC + PxW ]1;]2;]3;]4 + PxW ]5;]6;]7 +_EMStartUp MAC + Tool $206 + <<< +_EMShutDown MAC + Tool $306 + <<< +~EMVersion MAC + PHA +_EMVersion MAC + Tool $406 + <<< +_EMReset MAC + Tool $506 + <<< +~EMStatus MAC + PHA +_EMStatus MAC + Tool $606 + <<< +~DoWindows MAC + PHA +_DoWindows MAC + Tool $906 + <<< +~GetNextEvent MAC + PHA + PHWL ]1;]2 +_GetNextEvent MAC + Tool $A06 + <<< +~EventAvail MAC + PHA + PHWL ]1;]2 +_EventAvail MAC + Tool $B06 + <<< +~GetMouse MAC + PHL ]1 +_GetMouse MAC + Tool $C06 + <<< +~Button MAC + P1SW ]1 +_Button MAC + Tool $D06 + <<< +~StillDown MAC + P1SW ]1 +_StillDown MAC + Tool $E06 + <<< +~WaitMouseUp MAC + P1SW ]1 +_WaitMouseUp MAC + Tool $F06 + <<< +~TickCount MAC + PHS 2 +_TickCount MAC + Tool $1006 + <<< +~GetDblTime MAC + PHS 2 +_GetDblTime MAC + Tool $1106 + <<< +~GetCaretTime MAC + PHS 2 +_GetCaretTime MAC + Tool $1206 + <<< +_SetSwitch MAC + Tool $1306 + <<< +~PostEvent MAC + PHA + PHWL ]1;]2 +_PostEvent MAC + Tool $1406 + <<< +~FlushEvents MAC + PHA + PxW ]1;]2 +_FlushEvents MAC + Tool $1506 + <<< +~GetOSEvent MAC + PHA + PHWL ]1;]2 +_GetOSEvent MAC + Tool $1606 + <<< +~OSEventAvail MAC + PHA + PHWL ]1;]2 +_OSEventAvail MAC + Tool $1706 + <<< +~SetEventMask MAC + PHW ]1 +_SetEventMask MAC + Tool $1806 + <<< +~FakeMouse MAC + PxW ]1;]2;]3;]4 + PHW ]5 +_FakeMouse MAC + Tool $1906 + <<< +~SetAutoKeyLimit MAC + PHW ]1 +_SetAutoKeyLimit MAC + Tool $1A06 + <<< +~GetKeyTranslation MAC + P1SW ]1 +_GetKeyTranslation MAC + Tool $1B06 + <<< +~SetKeyTranslation MAC + PHW ]1 +_SetKeyTranslation MAC + Tool $1C06 + <<< +~qEMStartUp MAC + NextDP ]1;$100 + PxW ]2;]3;]4;]5 + PxW ]6;]7 + Tool $206 + <<< + diff --git a/Library/Female.Macs.s b/Library/Female.Macs.s new file mode 100644 index 0000000..368057c --- /dev/null +++ b/Library/Female.Macs.s @@ -0,0 +1,26 @@ +* +* Female Voice tool calls +* + +_FemaleBootInit mac + Tool $0133 + <<< +_FemaleStartUp mac + Tool $0233 + <<< +_FemaleShutDown mac + Tool $0333 + <<< +_FemaleVersion mac + Tool $0433 + <<< +_FemaleReset mac + Tool $0533 + <<< +_FemaleStatus mac + Tool $0633 + <<< +_FemaleSpeak mac + Tool $0933 + <<< + diff --git a/Library/Font.Macs.s b/Library/Font.Macs.s new file mode 100644 index 0000000..1b5313c --- /dev/null +++ b/Library/Font.Macs.s @@ -0,0 +1,142 @@ +* Font Manager macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_FMBootInit MAC + Tool $11B + <<< +~FMStartUp MAC + PxW ]1;]2 +_FMStartUp MAC + Tool $21B + <<< +_FMShutDown MAC + Tool $31B + <<< +~FMVersion MAC + PHA +_FMVersion MAC + Tool $41B + <<< +_FMReset MAC + Tool $51B + <<< +~FMStatus MAC + PHA +_FMStatus MAC + Tool $61B + <<< +~CountFamilies MAC + P1SW ]1 +_CountFamilies MAC + Tool $91B + <<< +~FindFamily MAC + P1SW ]1 + PHWL ]2;]3 +_FindFamily MAC + Tool $A1B + <<< +~GetFamInfo MAC + PHA + PHWL ]1;]2 +_GetFamInfo MAC + Tool $B1B + <<< +~GetFamNum MAC + P1SL ]1 +_GetFamNum MAC + Tool $C1B + <<< +~AddFamily MAC + PHWL ]1;]2 +_AddFamily MAC + Tool $D1B + <<< +~InstallFont MAC + PHLW ]1;]2 +_InstallFont MAC + Tool $E1B + <<< +~SetPurgeStat MAC + PHLW ]1;]2 +_SetPurgeStat MAC + Tool $F1B + <<< +~CountFonts MAC + P1SL ]1 + PHW ]2 +_CountFonts MAC + Tool $101B + <<< +~FindFontStats MAC + PHLW ]1;]2 + PHWL ]3;]4 +_FindFontStats MAC + Tool $111B + <<< +~LoadFont MAC + PHLW ]1;]2 + PHWL ]3;]4 +_LoadFont MAC + Tool $121B + <<< +_LoadSysFont MAC + Tool $131B + <<< +~AddFontVar MAC + PHLW ]1;]2 +_AddFontVar MAC + Tool $141B + <<< +~FixFontMenu MAC + PxW ]1;]2;]3 +_FixFontMenu MAC + Tool $151B + <<< +~ChooseFont MAC + P2SL ]1 + PHW ]2 +_ChooseFont MAC + Tool $161B + <<< +~ItemID2FamNum MAC + P1SW ]1 +_ItemID2FamNum MAC + Tool $171B + <<< +~FMSetSysFont MAC + PHL ]1 +_FMSetSysFont MAC + Tool $181B + <<< +~FMGetSysFID MAC + PHS 2 +_FMGetSysFID MAC + Tool $191B + <<< +~FMGetCurFID MAC + PHS 2 +_FMGetCurFID MAC + Tool $1A1B + <<< +~FamNum2ItemID MAC + P1SW ]1 +_FamNum2ItemID MAC + Tool $1B1B + <<< +~InstallWithStats MAC + PHLW ]1;]2 + PHL ]3 +_InstallWithStats MAC + Tool $1C1B + <<< +~qFMStartUp MAC + PHW ]1 + NextDP ]2;$100 + Tool $21B + <<< + diff --git a/Library/GsOs.Macs.s b/Library/GsOs.Macs.s new file mode 100644 index 0000000..8d1c974 --- /dev/null +++ b/Library/GsOs.Macs.s @@ -0,0 +1,39 @@ +* File: MGSOS +* +* Copyright 1989 by Dave Klimas +* +* IMPORTANT! To use these macros, you must also include the +* label equates as defined in the file E16.GSOS from the TOOL.EQUATES +* directory. +*----------------------------------------------- +* +* xGSOS ;;class 0/1 flag +* +* iGSOS _Create;addr;0 ;this is a class 0 Create call +* +*----------------------------------------------- +* Inline GS/OS call macro + +iGSOS MAC + JSL $E100A8 + DO ]3 + DA ]1.$2000 + ELSE + DA ]1 + FIN + ADRL ]2 + <<< + +*----------------------------------------------- +* Stack GS/OS call macro + +sGSOS MAC + PHL ]2 + DO ]3 + PEA ]1.$2000 + ELSE + PEA ]1 + FIN + JSL $E100B0 + <<< + diff --git a/Library/Int.Macs.s b/Library/Int.Macs.s new file mode 100644 index 0000000..13a5e88 --- /dev/null +++ b/Library/Int.Macs.s @@ -0,0 +1,221 @@ +* Integer Math macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_IMBootInit MAC + Tool $10B + <<< +_IMStartUp MAC +_IntStartUp MAC + Tool $20B + <<< +_IMShutDown MAC +_IntShutDown MAC + Tool $30B + <<< +~IMVersion MAC + PHA +_IMVersion MAC + Tool $40B + <<< +_IMReset MAC + Tool $50B + <<< +~IMStatus MAC + PHA +_IMStatus MAC + Tool $60B + <<< +~Multiply MAC + PHS 2 + PxW ]1;]2 +_Multiply MAC + Tool $90B + <<< +~SDivide MAC + PHS 2 + PxW ]1;]2 +_SDivide MAC + Tool $A0B + <<< +~UDivide MAC + PHS 2 + PxW ]1;]2 +_UDivide MAC + Tool $B0B + <<< +~LongMul MAC + PHS 4 + PxL ]1;]2 +_LongMul MAC + Tool $C0B + <<< +~LongDivide MAC + PHS 4 + PxL ]1;]2 +_LongDivide MAC + Tool $D0B + <<< +~FixRatio MAC + PHS 2 + PxW ]1;]2 +_FixRatio MAC + Tool $E0B + <<< +~FixMul MAC + PHS 2 + PxL ]1;]2 +_FixMul MAC + Tool $F0B + <<< +~FracMul MAC + PHS 2 + PxL ]1;]2 +_FracMul MAC + Tool $100B + <<< +~FixDiv MAC + PHS 2 + PxL ]1;]2 +_FixDiv MAC + Tool $110B + <<< +~FracDiv MAC + PHS 2 + PxL ]1;]2 +_FracDiv MAC + Tool $120B + <<< +~FixRound MAC + P1SL ]1 +_FixRound MAC + Tool $130B + <<< +~FracSqrt MAC + P2SL ]1 +_FracSqrt MAC + Tool $140B + <<< +~FracCos MAC + P2SL ]1 +_FracCos MAC + Tool $150B + <<< +~FracSin MAC + P2SL ]1 +_FracSin MAC + Tool $160B + <<< +~FixATan2 MAC + PHS 2 + PxL ]1;]2 +_FixATan2 MAC + Tool $170B + <<< +~HiWord MAC + P1SL ]1 +_HiWord MAC + Tool $180B + <<< +~LoWord MAC + P1SL ]1 +_LoWord MAC + Tool $190B + <<< +~Long2Fix MAC + P2SL ]1 +_Long2Fix MAC + Tool $1A0B + <<< +~Fix2Long MAC + P2SL ]1 +_Fix2Long MAC + Tool $1B0B + <<< +~Fix2Frac MAC + P2SL ]1 +_Fix2Frac MAC + Tool $1C0B + <<< +~Frac2Fix MAC + P2SL ]1 +_Frac2Fix MAC + Tool $1D0B + <<< +~Fix2X MAC + PxL ]1;]2 +_Fix2X MAC + Tool $1E0B + <<< +~Frac2X MAC + PxL ]1;]2 +_Frac2X MAC + Tool $1F0B + <<< +~X2Fix MAC + P2SL ]1 +_X2Fix MAC + Tool $200B + <<< +~X2Frac MAC + P2SL ]1 +_X2Frac MAC + Tool $210B + <<< +~Int2Hex MAC + PHW ]1 + PHLW ]2;]3 +_Int2Hex MAC + Tool $220B + <<< +~Long2Hex MAC + PxL ]1;]2 + PHW ]3 +_Long2Hex MAC + Tool $230B + <<< +~Hex2Int MAC + PHA + PHLW ]1;]2 +_Hex2Int MAC + Tool $240B + <<< +~Hex2Long MAC + PHS 2 + PHLW ]1;]2 +_Hex2Long MAC + Tool $250B + <<< +~Int2Dec MAC + PHWL ]1;]2 + PxW ]3;]4 +_Int2Dec MAC + Tool $260B + <<< +~Long2Dec MAC + PxL ]1;]2 + PxW ]3;]4 +_Long2Dec MAC + Tool $270B + <<< +~Dec2Int MAC + P1SL ]1 + PxW ]2;]3 +_Dec2Int MAC + Tool $280B + <<< +~Dec2Long MAC + P2SL ]1 + PxW ]2;]3 +_Dec2Long MAC + Tool $290B + <<< +~HexIt MAC + P2SW ]1 +_HexIt MAC + Tool $2A0B + <<< + diff --git a/Library/Line.Macs.s b/Library/Line.Macs.s new file mode 100644 index 0000000..075a940 --- /dev/null +++ b/Library/Line.Macs.s @@ -0,0 +1,183 @@ +* LineEdit macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_LEBootInit MAC + Tool $114 + <<< +~LEStartUp MAC + PxW ]1;]2 +_LEStartUp MAC + Tool $214 + <<< +_LEShutDown MAC + Tool $314 + <<< +~LEVersion MAC + PHA +_LEVersion MAC + Tool $414 + <<< +_LEReset MAC + Tool $514 + <<< +~LEStatus MAC + PHA +_LEStatus MAC + Tool $614 + <<< +~LENew MAC + P2SL ]1 + PHLW ]2;]3 +_LENew MAC + Tool $914 + <<< +~LEDispose MAC + PHL ]1 +_LEDispose MAC + Tool $A14 + <<< +~LESetText MAC + PHL ]1 + PHWL ]2;]3 +_LESetText MAC + Tool $B14 + <<< +~LEIdle MAC + PHL ]1 +_LEIdle MAC + Tool $C14 + <<< +~LEClick MAC + PxL ]1;]2 +_LEClick MAC + Tool $D14 + <<< +~LESetSelect MAC + PxW ]1;]2 + PHL ]3 +_LESetSelect MAC + Tool $E14 + <<< +~LEActivate MAC + PHL ]1 +_LEActivate MAC + Tool $F14 + <<< +~LEDeactivate MAC + PHL ]1 +_LEDeactivate MAC + Tool $1014 + <<< +~LEKey MAC + PxW ]1;]2 + PHL ]3 +_LEKey MAC + Tool $1114 + <<< +~LECut MAC + PHL ]1 +_LECut MAC + Tool $1214 + <<< +~LECopy MAC + PHL ]1 +_LECopy MAC + Tool $1314 + <<< +~LEPaste MAC + PHL ]1 +_LEPaste MAC + Tool $1414 + <<< +~LEDelete MAC + PHL ]1 +_LEDelete MAC + Tool $1514 + <<< +~LEInsert MAC + PHL ]1 + PHWL ]2;]3 +_LEInsert MAC + Tool $1614 + <<< +~LEUpdate MAC + PHL ]1 +_LEUpdate MAC + Tool $1714 + <<< +~LETextBox MAC + PHLW ]1;]2 + PHLW ]3;]4 +_LETextBox MAC + Tool $1814 + <<< +_LEFromScrap MAC + Tool $1914 + <<< +_LEToScrap MAC + Tool $1A14 + <<< +~LEScrapHandle MAC + PHS 2 +_LEScrapHandle MAC + Tool $1B14 + <<< +~LEGetScrapLen MAC + PHA +_LEGetScrapLen MAC + Tool $1C14 + <<< +~LESetScrapLen MAC + PHW ]1 +_LESetScrapLen MAC + Tool $1D14 + <<< +~LESetHilite MAC + PxL ]1;]2 +_LESetHilite MAC + Tool $1E14 + <<< +~LESetCaret MAC + PxL ]1;]2 +_LESetCaret MAC + Tool $1F14 + <<< +~LETextBox2 MAC + PHLW ]1;]2 + PHLW ]3;]4 +_LETextBox2 MAC + Tool $2014 + <<< +~LESetJust MAC + PHWL ]1;]2 +_LESetJust MAC + Tool $2114 + <<< +~LEGetTextHand MAC + P2SL ]1 +_LEGetTextHand MAC + Tool $2214 + <<< +~LEGetTextLen MAC + P1SL ]1 +_LEGetTextLen MAC + Tool $2314 + <<< +~GetLEDefProc MAC + PHS 2 +_GetLEDefProc MAC + Tool $2414 + <<< +~qLEStartUp MAC + PHW ]1 + NextDP ]2;$100 + Tool $214 + <<< +_LEClassifyKey MAC + Tool $2514 + <<< + diff --git a/Library/List.Macs.s b/Library/List.Macs.s new file mode 100644 index 0000000..552e105 --- /dev/null +++ b/Library/List.Macs.s @@ -0,0 +1,111 @@ +* List Mgr. macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_ListBootInit MAC + Tool $011C + <<< +_ListStartup MAC + Tool $021C + <<< +_ListShutDown MAC + Tool $031C + <<< +~ListVersion MAC + PHA +_ListVersion MAC + Tool $041C + <<< +_ListReset MAC + Tool $051C + <<< +~ListStatus MAC + PHA +_ListStatus MAC + Tool $061C + <<< +~CreateList MAC + PHS 2 + PxL ]1;]2 +_CreateList MAC + Tool $091C + <<< +~SortList MAC + PxL ]1;]2 +_SortList MAC + Tool $0A1C + <<< +~NextMember MAC + PHS 2 + PxL ]1;]2 +_NextMember MAC + Tool $0B1C + <<< +~DrawMember MAC + PxL ]1;]2 +_DrawMember MAC + Tool $0C1C + <<< +~SelectMember MAC + PxL ]1;]2 +_SelectMember MAC + Tool $0D1C + <<< +~GetListDefProc MAC + PHS 2 +_GetListDefProc MAC + Tool $0E1C + <<< +~ResetMember MAC + P2SL ]1 +_ResetMember MAC + Tool $0F1C + <<< +~NewList MAC + PxL ]1;]2 +_NewList MAC + Tool $101C + <<< +~DrawMember2 MAC + PHWL ]1;]2 +_DrawMember2 MAC + Tool $111C + <<< +~NextMember2 MAC + PHA + PHWL ]1;]2 +_NextMember2 MAC + Tool $121C + <<< +~ResetMember2 MAC + P1SL ]1 +_ResetMember2 MAC + Tool $131C + <<< +~SelectMember2 MAC + PHWL ]1;]2 +_SelectMember2 MAC + Tool $141C + <<< +~SortList2 MAC + PxL ]1;]2 +_SortList2 MAC + Tool $151C + <<< +~NewList2 MAC + PHL ]1 + PxW ]2;]3;]4;]5 + PHL ]6 +_NewList2 MAC + Tool $161C + <<< +_ListKey MAC + Tool $171C + <<< +_CompareStrings MAC + Tool $181C + <<< + diff --git a/Library/Load.Macs.s b/Library/Load.Macs.s new file mode 100644 index 0000000..925855a --- /dev/null +++ b/Library/Load.Macs.s @@ -0,0 +1,113 @@ +* Load Manager macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_LoaderInitialization MAC + Tool $111 + <<< +_LoaderStartUp MAC + Tool $211 + <<< +_LoaderShutDown MAC + Tool $311 + <<< +~LoaderVersion MAC + PHA +_LoaderVersion MAC + Tool $411 + <<< +_LoaderReset MAC + Tool $511 + <<< +~LoaderStatus MAC + PHA +_LoaderStatus MAC + Tool $611 + <<< +~InitialLoad MAC + PHS 5 + PHWL ]1;]2 + PHW ]3 +_InitialLoad MAC + Tool $911 + <<< +~InitialLoad2 MAC + PHS 5 + PHWL ]1;]2 + PxW ]3;]4 +_InitialLoad2 MAC + Tool $2011 + <<< +~Restart MAC + PHS 5 + PHW ]1 +_Restart MAC + Tool $A11 + <<< +~LoadSegNum MAC + PHS 2 + PxW ]1;]2;]3 +_LoadSegNum MAC + Tool $B11 + <<< +~UnloadSegNum MAC + PxW ]1;]2;]3 +_UnloadSegNum MAC + Tool $C11 + <<< +~LoadSegName MAC + PHS 4 + PHW ]1 + PxL ]2;]3 +_LoadSegName MAC + Tool $D11 + <<< +~UnloadSeg MAC + PHS 3 + PHL ]1 +_UnloadSeg MAC + Tool $E11 + <<< +~GetLoadSegInfo MAC + PxW ]1;]2;]3 + PHL ]4 +_GetLoadSegInfo MAC + Tool $F11 + <<< +~GetUserID MAC + P1SL ]1 +_GetUserID MAC + Tool $1011 + <<< +~GetUserID2 MAC + P1SL ]1 +_GetUserID2 MAC + Tool $2111 + <<< +~LGetPathname MAC + PHS 2 + PxW ]1;]2 +_LGetPathname MAC + Tool $1111 + <<< +~LGetPathname2 MAC + PHS 2 + PxW ]1;]2 +_LGetPathname2 MAC + Tool $2211 + <<< +~UserShutDown MAC + PHA + PxW ]1;]2 +_UserShutDown MAC + Tool $1211 + <<< +~RenamePathname MAC + PxL ]1;]2 +_RenamePathname MAC + Tool $1311 + <<< + diff --git a/Library/Locator.Macs.s b/Library/Locator.Macs.s new file mode 100644 index 0000000..3878722 --- /dev/null +++ b/Library/Locator.Macs.s @@ -0,0 +1,135 @@ +* Tool Locator macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_TLBootInit MAC + Tool $101 + <<< +_TLStartUp MAC + Tool $201 + <<< +_TLShutDown MAC + Tool $301 + <<< +~TLVersion MAC + PHA +_TLVersion MAC + Tool $401 + <<< +_TLReset MAC + Tool $501 + <<< +~TLStatus MAC + PHA +_TLStatus MAC + Tool $601 + <<< +~GetTSPtr MAC + PHS 2 + PxW ]1;]2 +_GetTSPtr MAC + Tool $901 + <<< +~SetTSPtr MAC + PxW ]1;]2 + PHL ]3 +_SetTSPtr MAC + Tool $A01 + <<< +~GetFuncPtr MAC + PHS 2 + PxW ]1;]2 +_GetFuncPtr MAC + Tool $B01 + <<< +~GetWAP MAC + PHS 2 + PxW ]1;]2 +_GetWAP MAC + Tool $C01 + <<< +~SetWAP MAC + PxW ]1;]2 + PHL ]3 +_SetWAP MAC + Tool $D01 + <<< +~LoadTools MAC + PHL ]1 +_LoadTools MAC + Tool $E01 + <<< +~LoadOneTool MAC + PxW ]1;]2 +_LoadOneTool MAC + Tool $F01 + <<< +~UnloadOneTool MAC + PHW ]1 +_UnloadOneTool MAC + Tool $1001 + <<< +~TLMountVolume MAC + PHA + PxW ]1;]2 + PxL ]3;]4;]5;]6 +_TLMountVolume MAC + Tool $1101 + <<< +~TLTextMountVolume MAC + PHA + PxL ]1;]2;]3;]4 +_TLTextMountVolume MAC + Tool $1201 + <<< +~SaveTextState MAC + PHS 2 +_SaveTextState MAC + Tool $1301 + <<< +~RestoreTextState MAC + PHL ]1 +_RestoreTextState MAC + Tool $1401 + <<< +~MessageCenter MAC + PxW ]1;]2 + PHL ]3 +_MessageCenter MAC + Tool $1501 + <<< +_SetDefaultTPT MAC + Tool $1601 + <<< +~MessageByName MAC + PHS 2 + PHWL ]1;]2 + PxW ]3;]4 +_MessageByName MAC + Tool $1701 + <<< +~StartUpTools MAC + PHA + PxW ]1;]2 + PxL ]3;]4 +_StartUpTools MAC + Tool $1801 + <<< +~ShutDownTools MAC + PHWL ]1;]2 +_ShutDownTools MAC + Tool $1901 + <<< +_GetMsgHandle MAC + Tool $1A01 + <<< +_AcceptRequests MAC + Tool $1B01 + <<< +_SendRequest MAC + Tool $1C01 + <<< + diff --git a/Library/Logo.Macs.s b/Library/Logo.Macs.s new file mode 100644 index 0000000..83155c3 --- /dev/null +++ b/Library/Logo.Macs.s @@ -0,0 +1,87 @@ +*----------------------------- +* LoGo's useful tools... +*----------------------------- + +_En8 mac + sec + xce + sep #$30 + <<< + +_En16 mac + clc + xce + rep #$30 + <<< + +_ClrScr mac + ldx #$7ffe + lda #$0000 +]lp stal $e12000,x + stal $012000,x + dex + dex + bpl ]lp + <<< + +_fadeIN mac ; Fait un fondu de l'image + lda ]1 ; A= banc/adrh de l'image + ldy ]2 ; Y= $0000, fondu sur l'image + jsr fadeIN ; $ffff, que sur les palettes + <<< + +_fadeOUT mac ; Efface l'ecran doucement + jsr fadeOUT + <<< + +_File mac ; Charge un fichier + lda ]1 + ldx ]2 + jsr loadFILE + <<< + +_Key mac ; Attend une touche au clavier +]lp ldal $e0bfff + bpl ]lp + stal $e0c010 + <<< + +_Unpack mac ; Decompacte un fichier + lda ]1 ; A= banc/adrh du fichier source + jsr unPACK + <<< + +_wait mac ; Routine d'attente + lda ]1 ; A= duree d'attente (env. 1 seconde) + jsr nowWAIT + eom + +_Write8 mac ; Affiche un message + lda ]1 ; A= adresse de la chaine + ldx ]2 ; X= coordonnee sur l'ecran + ldy ]3 ; Y= banc/adrh ou afficher + jsr Print8 + <<< + +_Write16 mac ; Affiche un message + lda ]1 ; A= adresse de la chaine + ldx ]2 ; X= coordonnee sur l'ecran + ldy ]3 ; Y= banc/adrh ou afficher + jsr Print16 + <<< + +_Reset mac + lda #$51 + sta $0 + PushWord #2 + PushWord #0 + PushWord #0 + PushWord #8 + Tool $0909 + sec + xce + lda #0 + stal $0003f4 + jmp ($fffc) + <<< + diff --git a/Library/Macros.s b/Library/Macros.s new file mode 100644 index 0000000..dd612e0 --- /dev/null +++ b/Library/Macros.s @@ -0,0 +1,571 @@ +*------------------------- +* Macro library +*------------------------- + +INCD MAC ;Two byte INC + INC ]1 + IF MX>1 + BNE NC + INC ]1+1 +NC FIN + <<< + +DECD MAC ;Two byte DEC + IF MX>1 + LDA ]1 + BNE NC + DEC ]1+1 +NC FIN + DEC ]1 + <<< + +MOV MAC + LDA ]1 + STA ]2 + <<< + +MOVD MAC + MOV ]1;]2 + IF MX>1 ;If A is short + IF (=]1 ;Syntax MOVD (ADR1),Y;???? + INY + IF (=]2 ; MOVD (ADR1),Y;(ADR2),Y + MOV ]1;]2 + ELSE ; MOVD (ADR1),Y;ADR2 + MOV ]1;]2+1 + FIN + ELSE + IF (=]2 ;Syntax MOVD ????;(ADR2),Y + INY + IF #=]1 ; MOVD #ADR1;(ADR2),Y + MOV ]1/$100;]2 + ELSE ; MOVD ADR1;(ADR2),Y + MOV ]1+1;]2 + FIN + ELSE ;Syntax MOVD ????;ADR2 + IF #=]1 ; MOVD #ADR1;ADR2 + MOV ]1/$100;]2+1 + ELSE ; MOVD ADR1;ADR2 + MOV ]1+1;]2+1 + FIN + FIN + FIN + FIN + <<< + +LDHI MAC ;For calls from other macs + IF #=]1 + LDA ]1/$100 + ELSE + LDA ]1+1 + FIN + <<< + +ADD MAC + IF #=]2 + IF #=]1 + ERR 1 ;Error if ADD #lab1;#lab2.. + FIN + FIN + CLC + LDA ]1 ;Syntax ADD lab1;lab2;lab3 + ADC ]2 ; or ADD #lab1;lab2;lab3 etc + DO ]0/3 + STA ]3 ;If 3 parms + ELSE ;2 parm cases: + IF #=]2 + STA ]1 ;Syntax ADD lab1;#lab2 + ELSE ;Syntax ADD lab1;lab2 + STA ]2 ; or ADD #lab1;lab2 -> lab2 + FIN + FIN + IF MX>1 ;Following ignored if M long + LDA ]1+1 + IF #=]2 + ADC ]2/$100 + ELSE + ADC ]2+1 + FIN + DO ]0/3 + STA ]3+1 ;If 3 parms + ELSE ;Two parm cases: + IF #=]2 + STA ]1+1 ;Syntax ADD lab1;#lab2 + ELSE ; -> lab1 + STA ]2+1 ;Syntax ADD lab1;lab2 -> lab2 + FIN ; or ADD #lab1;lab2 -> lab2 + FIN + FIN + <<< + +SUB MAC + IF #=]2 + IF #=]1 + ERR 1 ;Error if SUB #lab1;#lab2.. + FIN + FIN + SEC + LDA ]1 ;Syntax SUB lab1;lab2;lab3 + SBC ]2 ; or SUB #lab1;lab2;lab3 etc + DO ]0/3 + STA ]3 ;If 3 parms + ELSE ;Two parm cases: + IF #=]2 + STA ]1 ;Syntax SUB lab1;#lab2 + ELSE ;Syntax SUB lab1;lab2 + STA ]2 ; or SUB #lab1;lab2 -> lab2 + FIN + FIN ;Of 2 parm cases + IF MX>1 ;Rest ignored if M long + LDHI ]1 + IF #=]2 + SBC ]2/$100 ;Case #lab2 + ELSE + SBC ]2+1 ;Case lab2 + FIN + DO ]0/3 + STA ]3+1 ;If 3 parms + ELSE ;Two parm cases: + IF #=]2 + STA ]1+1 ;Syntax SUB lab1;#lab2 + ELSE ; -> lab1 + STA ]2+1 ;Syntax SUB lab1;lab2 -> lab2 + FIN ; or SUB #lab1;lab2 -> lab2 + FIN ;Of 2 parm cases + FIN ;Of M short + <<< + +ADDX MAC + TXA +ADDA MAC + CLC + ADC ]1 + STA ]2 + IF MX>1 + LDHI ]1 + ADC #0 + STA ]2+1 + FIN + <<< + +ADDY MAC + TYA + ADDA ]1;]2 + <<< + +ADDNUM MAC + LDA #]1 + CLC + ADC ]2 + STA ]2 + IF MX>1 + BCC NC + INC ]2+1 +NC FIN + <<< + +SWAP MAC + LDA ]1 + PHA + LDA ]2 + STA ]1 + PLA + STA ]2 + <<< + +COMPARE MAC + LDA ]1 + CMP ]2 + IF MX>1 + LDHI ]1 ;Syntax COMPARE lab1;lab2 + IF #=]2 ; or COMPARE lab1;#lab2 + SBC ]2/$100 + ELSE + SBC ]2+1 + FIN + FIN + <<< + +POKE MAC + MOV #]2;]1 + <<< + +STADR MAC + POKE ]2;]1 + IF MX>1 ;If M is short, do high byte + POKE ]2+1;]1/$100 + FIN + <<< + +*================================================= +* Save and restore registers macros. Recommended +* for use at the start and end of subroutines +* which might be called from unknown status and +* which must set up register lengths. +*------------------------------------------------- + +SAVSTAT MAC ;Save registers & status + PHA + PHY + PHX + PHP + <<< + +RESTORE MAC ;Restore regs & status + PLP ;This must come first + PLX ; so register restores + PLY ; have correct length. + PLA + <<< + +*================================================= +* Conditional branches not available on the 65816: +*------------------------------------------------- + +BLE MAC ;Branch if less than or = + BEQ ]1 + BLT ]1 + <<< + +BGT MAC ;Branch if greater than + BEQ OV + BGE ]1 +OV <<< + +*================================================= +* Conditional long branches. For use when out of +* range of a short branch and branching mechanism +* is wanted to be hidden on the listing. +*------------------------------------------------- + +BRTL MAC ;BRL if less than (long) +BCCL MAC ;BRL if carry clear (long) + BCS OV + BRL ]1 +OV <<< + +BGEL MAC ;BRL if greater or equal (long) +BCSL MAC ;BRL if carry set (long) + BCC OV + BRL ]1 +OV <<< + +BPLL MAC ;BRL if plus (long) + BMI OV + BRL ]1 +OV <<< + +BMIL MAC ;BRL if minus (long) + BPL OV + BRL ]1 +OV <<< + +BEQL MAC ;BRL if equal (long) + BNE OV + BRL ]1 +OV <<< + +BNEL MAC ;BRL if not equal (long) + BEQ OV + BRL ]1 +OV <<< + +BVCL MAC ;BRL if V clear (long) + BVS OV + BRL ]1 +OV <<< + +BVSL MAC ;BRL if V set (long) + BVC OV + BRL ]1 +OV <<< + +BLEL MAC ;BRL if less or equal (long) + BEQ BR + BGE OV +BR BRL ]1 +OV <<< + +BLTL MAC ;BRL if less than (long) + BGE OV + BRL ]1 +OV <<< + +BGTL MAC ;BRL if greater than (long) + BEQ OV + BLT OV +BR BRL ]1 +OV <<< + +*================================================= +* The I/O macros below expect the COUT routine +* to be included or linked in as an external. +* PRINT expects the same of the SENDMSG routine. +* +* (Just declare COUT and SENDMSG as externals +* and include the linker command LIB 5 in the +* linker command file. SENDMSG also requires an +* OUTPUT routine in your source declared as an +* entry. It can be as simple as: +* +* OUTPUT JMP COUT +* +* SENDMSG and COUT are in the LIB directory and +* their source files are in the SOURCE directory. +*------------------------------------------------- + +PRINT MAC ;Syntax PRINT "message" + JSR SENDMSG ; or PRINT 8D8D or + ASC ]1 ; PRINT 8D8D"text"8D"more" + BRK ; etc. + <<< + +OUT MAC + LDA ]1 ;Syntax OUT #"A" + JSR COUT ; or OUT ADDRESS + <<< ; or OUT (PNT),Y etc. + +HOME MAC ;Clear 80 col screen + OUT #"L"&$9F + <<< + +NORMAL MAC ;Set normal text + OUT #"N"&$9F + <<< + +INVERSE MAC ;Set inverse text + OUT #"O"&$9F + <<< + +MOUSEON MAC ;Turn mousetext on + OUT #"["&$9F + INVERSE + <<< + +MOUSEOFF MAC ;Turn mousetext off + OUT #"X"&$9F + NORMAL + <<< + +BELL MAC ;Ring bell + OUT #"G"&$9F + <<< + +CLEOL MAC ;Clear to end of line + OUT #$9D + <<< + +CLEOP MAC ;Clear to end of screen + OUT #$8B + <<< + +OUTCR MAC ;Do carriage return + OUT #$8D + <<< + +GOTOXY MAC ;Pascal output only! + OUT #$1E + LDA ]1 ;X coor (imm or location) + CLC + ADC #' ' + JSR COUT + LDA ]2 ;Y coor (") + CLC + ADC #' ' + JSR COUT + <<< + +CURSXY MAC ;GOTOXY for BASIC output + OUT #"Y"&$9F ;Home cursor + LDX ]2 ;Syntax (both versions): + BEQ H ; CURSXY #55;#10 or +CR OUTCR ; CURSXY XLOC,YLOC etc. + DEX + BNE CR +H IF MX<2 ;If M is long then + SEP %00100000 ; must shorten it + LDA ]1 + STAL $24 + REP %00100000 ; and lengthen on exit. + ELSE ;If M is short then + LDA ]1 ; leave as is + STAL $24 + FIN + <<< + +************************************************** +* APW-Equivalent Macros 1/20/89 * +* For use with APW or ORCA/M source listings. * +* * +************************************************** + +*================================================ + +DP MAC + ADRL ]1 + <<< + +ASL4 MAC + LDA ]1+2 + DO ]0/2 ;If 2 parms then set + LDX ]2 ; X to 2nd parm. + FIN +]A ASL ;Otherwise use X to + ASL ]1 ; decide how many + ADC #0 ; ASL's to do. + DEX + BNE ]A + STA ]1+2 + <<< + +LSR4 MAC + DO ]0/2 ;If 2 parms, then COMPLEMENT + LDA ]2 ; of X must be 2nd parm. + EOR $FFFF + CLC + ADC #1 + TAX + FIN + LDA ]1 +]A LSR + LSR ]1+2 + BCC ]B + ORA #$8000 +]B INX + BNE ]A + STA ]1 + <<< + +DEC4 MAC + IF MX/2-1 ; IF M IS SHORT + ERR 1 ; ERR IF NOT 16-BIT MODE + ELSE + DEC ]1 + BPL ]A + DEC ]1+2 +]A FIN + <<< + +INC4 MAC + IF MX/2-1 ; IF M IS SHORT + ERR 1 ; ERR IF NOT 16-BIT MODE + ELSE + INC ]1 + BNE ]A + INC ]1+2 +]A FIN + <<< + +ADD4 MAC + CLC ;If 3 parms then use + DO ]0/3 ; raw 4 byte addresses. + + IF #=]1 + LDA #<]1 + ELSE ;Make sure we use the + LDA ]1 ; right LDA for data + FIN ; or addresses. + + IF #=]2 + ADC #<]2 + ELSE ;Make sure we use the + ADC ]2 ; right ADC for data + FIN ; or addresses. + + STA ]3 + + IF #=]1 + LDA #^]1 + ELSE ;Make sure we use the + LDA ]1+2 ; right LDA for data + FIN ; or addresses. + + IF #=]2 + ADC #^]2 + ELSE ;Make sure we use the + ADC ]2+2 ; right ADC for data + FIN ; or addresses. + + STA ]3+2 + + ELSE ;If 2 parms then use +; 2 byte Accumulator. + + + IF #=]1 + ADC #<]1 + ELSE ;Make sure we use the + ADC ]1 ; right ADC for data + FIN ; or addresses. + + STA ]2 + + + IF #=]1 + LDA #^]1 + ELSE ;Make sure we use the + LDA ]1+2 ; right LDA for data + FIN ; or addresses. + + ADC #0 + STA ]2+2 + + FIN + <<< + +SUB4 MAC + SEC ;If 3 parms then use + DO ]0/3 ; raw 4 byte addresses. + + + IF #=]1 + LDA #<]1 + ELSE ;Make sure we use the + LDA ]1 ; right LDA for data + FIN ; or addresses. + + IF #=]2 + SBC #<]2 + ELSE ;Make sure we use the + SBC ]2 ; right SBC for data + FIN ; or addresses. + + STA ]3 + + + IF #=]1 + LDA #^]1 + ELSE ;Make sure we use the + LDA ]1+2 ; right LDA for data + FIN ; or addresses. + + IF #=]2 + SBC #^]2 + ELSE ;Make sure we use the + SBC ]2+2 ; right SBC for data + FIN ; or addresses. + + STA ]3+2 + + ELSE + + IF #=]1 + SBC #<]1 + ELSE ;Make sure we use the + SBC ]1 ; right SBC for data + FIN ; or addresses. + + STA ]2 + + IF #=]1 + LDA #^]1 + ELSE ;Make sure we use the + LDA ]1+2 ; right LDA for data + FIN ; or addresses. + + SBC #0 + STA ]2+2 + + FIN + <<< + diff --git a/Library/Male.Macs.s b/Library/Male.Macs.s new file mode 100644 index 0000000..9b2056e --- /dev/null +++ b/Library/Male.Macs.s @@ -0,0 +1,26 @@ +* +* Male Voice tool calls +* + +_MaleBootInit mac + Tool $0132 + <<< +_MaleStartUp mac + Tool $0232 + <<< +_MaleShutDown mac + Tool $0332 + <<< +_MaleVersion mac + Tool $0432 + <<< +_MaleReset mac + Tool $0532 + <<< +_MaleStatus mac + Tool $0632 + <<< +_MaleSpeak mac + Tool $0932 + <<< + diff --git a/Library/Media.Macs.s b/Library/Media.Macs.s new file mode 100644 index 0000000..bcb057c --- /dev/null +++ b/Library/Media.Macs.s @@ -0,0 +1,137 @@ +* +* Media Controller tool calls +* + +_MCBootInit mac + Tool $0126 + <<< +_MCStartUp mac + Tool $0226 + <<< +_MCShutDown mac + Tool $0326 + <<< +_MCVersion mac + Tool $0426 + <<< +_MCReset mac + Tool $0526 + <<< +_MCStatus mac + Tool $0626 + <<< +_MCGetErrorMsg mac + Tool $0926 + <<< +_MCLoadDriver mac + Tool $0a26 + <<< +_MCUnLoadDriver mac + Tool $0b26 + <<< +_MCTime2Bin mac + Tool $0c26 + <<< +_MCBin2Time mac + Tool $0d26 + <<< +_MCGetTrackTitle mac + Tool $0e26 + <<< +_MCSetTrackTitle mac + Tool $0f26 + <<< +_MCGetProgram mac + Tool $1026 + <<< +_MCSetProgram mac + Tool $1126 + <<< +_MCGetDiscTitle mac + Tool $1226 + <<< +_MCSetDiscTitle mac + Tool $1326 + <<< +_MCDStartUp mac + Tool $1426 + <<< +_MCDShutDown mac + Tool $1526 + <<< +_MCGetFeatures mac + Tool $1626 + <<< +_MCPlay mac + Tool $1726 + <<< +_MCPause mac + Tool $1826 + <<< +_MCSendRawData mac + Tool $1926 + <<< +_MCGetStatus mac + Tool $1a26 + <<< +_MCControl mac + Tool $1b26 + <<< +_MCScan mac + Tool $1c26 + <<< +_MCGetSpeeds mac + Tool $1d26 + <<< +_MCSpeed mac + Tool $1e26 + <<< +_MCStopAt mac + Tool $1f26 + <<< +_MCJog mac + Tool $2026 + <<< +_MCSearchTo mac + Tool $2126 + <<< +_MCSearchDone mac + Tool $2226 + <<< +_MCSearchWait mac + Tool $2326 + <<< +_MCGetPosition mac + Tool $2426 + <<< +_MCSetAudio mac + Tool $2526 + <<< +_MCGetTimes mac + Tool $2626 + <<< +_MCGetDiscTOC mac + Tool $2726 + <<< +_MCGetDiscID mac + Tool $2826 + <<< +_MCGetNoTracks mac + Tool $2926 + <<< +_MCRecord mac + Tool $2a26 + <<< +_MCStop mac + Tool $2b26 + <<< +_MCWaitRawData mac + Tool $2c26 + <<< +_MCGetName mac + Tool $2d26 + <<< +_MCSetVolume mac + Tool $2e26 + <<< + diff --git a/Library/Mem.Macs.s b/Library/Mem.Macs.s new file mode 100644 index 0000000..be9ddb2 --- /dev/null +++ b/Library/Mem.Macs.s @@ -0,0 +1,179 @@ +* Memory Manager macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_MMBootInit MAC + Tool $102 + <<< +~MMStartUp MAC + PHA +_MMStartUp MAC + Tool $202 + <<< +~MMShutDown MAC + PHW ]1 +_MMShutDown MAC + Tool $302 + <<< +~MMVersion MAC + PHA +_MMVersion MAC + Tool $402 + <<< +_MMReset MAC + Tool $502 + <<< +~MMStatus MAC + PHA +_MMStatus MAC + Tool $602 + <<< +~NewHandle MAC + P2SL ]1 + PxW ]2;]3 + PHL ]4 +_NewHandle MAC + Tool $902 + <<< +~ReallocHandle MAC + PHLW ]1;]2 + PHWL ]3;]4 + PHL ]5 +_ReallocHandle MAC + Tool $A02 + <<< +~RestoreHandle MAC + PHL ]1 +_RestoreHandle MAC + Tool $B02 + <<< +~AddToOOMQueue MAC + PHL ]1 +_AddToOOMQueue MAC + Tool $C02 + <<< +~DeleteFromOOMQueue MAC + PHL ]1 +_DeleteFromOOMQueue MAC + Tool $D02 + <<< +~DisposeHandle MAC + PHL ]1 +_DisposeHandle MAC + Tool $1002 + <<< +~DisposeAll MAC + PHW ]1 +_DisposeAll MAC + Tool $1102 + <<< +~PurgeHandle MAC + PHL ]1 +_PurgeHandle MAC + Tool $1202 + <<< +~PurgeAll MAC + PHW ]1 +_PurgeAll MAC + Tool $1302 + <<< +~GetHandleSize MAC + P2SL ]1 +_GetHandleSize MAC + Tool $1802 + <<< +~SetHandleSize MAC + PxL ]1;]2 +_SetHandleSize MAC + Tool $1902 + <<< +~FindHandle MAC + P2SL ]1 +_FindHandle MAC + Tool $1A02 + <<< +~FreeMem MAC + PHS 2 +_FreeMem MAC + Tool $1B02 + <<< +~MaxBlock MAC + PHS 2 +_MaxBlock MAC + Tool $1C02 + <<< +~TotalMem MAC + PHS 2 +_TotalMem MAC + Tool $1D02 + <<< +~CheckHandle MAC + PHL ]1 +_CheckHandle MAC + Tool $1E02 + <<< +_CompactMem MAC + Tool $1F02 + <<< +~HLock MAC + PHL ]1 +_HLock MAC + Tool $2002 + <<< +~HLockAll MAC + PHW ]1 +_HLockAll MAC + Tool $2102 + <<< +~HUnlock MAC + PHL ]1 +_HUnlock MAC + Tool $2202 + <<< +~HUnlockAll MAC + PHW ]1 +_HUnlockAll MAC + Tool $2302 + <<< +~SetPurge MAC + PHWL ]1;]2 +_SetPurge MAC + Tool $2402 + <<< +~SetPurgeAll MAC + PxW ]1;]2 +_SetPurgeAll MAC + Tool $2502 + <<< +~PtrToHand MAC + PxL ]1;]2;]3 +_PtrToHand MAC + Tool $2802 + <<< +~HandToPtr MAC + PxL ]1;]2;]3 +_HandToPtr MAC + Tool $2902 + <<< +~HandToHand MAC + PxL ]1;]2;3 +_HandToHand MAC + Tool $2A02 + <<< +~BlockMove MAC + PxL ]1;]2;]3 +_BlockMove MAC + Tool $2B02 + <<< +~RealFreeMem MAC + PHS 2 +_RealFreeMem MAC + Tool $2F02 + <<< +_SetHandleID MAC + Tool $3002 + <<< + diff --git a/Library/Menu.Macs.s b/Library/Menu.Macs.s new file mode 100644 index 0000000..f8942ab --- /dev/null +++ b/Library/Menu.Macs.s @@ -0,0 +1,372 @@ +* Menu Manager macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_MenuBootInit MAC + Tool $10F + <<< +~MenuStartUp MAC + PxW ]1;]2 +_MenuStartUp MAC + Tool $20F + <<< +_MenuShutDown MAC + Tool $30F + <<< +~MenuVersion MAC + PHA +_MenuVersion MAC + Tool $40F + <<< +_MenuReset MAC + Tool $50F + <<< +~MenuStatus MAC + PHA +_MenuStatus MAC + Tool $60F + <<< +~MenuKey MAC + PxL ]1;]2 +_MenuKey MAC + Tool $90F + <<< +~GetMenuBar MAC + PHS 2 +_GetMenuBar MAC + Tool $A0F + <<< +~MenuRefresh MAC + PHL ]1 +_MenuRefresh MAC + Tool $B0F + <<< +_FlashMenuBar MAC + Tool $C0F + <<< +~InsertMenu MAC + PHLW ]1;]2 +_InsertMenu MAC + Tool $D0F + <<< +~DeleteMenu MAC + PHW ]1 +_DeleteMenu MAC + Tool $E0F + <<< +~InsertMItem MAC + PHL ]1 + PxW ]2;]3 +_InsertMItem MAC + Tool $F0F + <<< +~DeleteMItem MAC + PHW ]1 +_DeleteMItem MAC + Tool $100F + <<< +~GetSysBar MAC + PHS 2 +_GetSysBar MAC + Tool $110F + <<< +~SetSysBar MAC + PHL ]1 +_SetSysBar MAC + Tool $120F + <<< +~FixMenuBar MAC + PHA +_FixMenuBar MAC + Tool $130F + <<< +~CountMItems MAC + P1SW ]1 +_CountMItems MAC + Tool $140F + <<< +~NewMenuBar MAC + P2SL ]1 +_NewMenuBar MAC + Tool $150F + <<< +~GetMHandle MAC + P2SW ]1 +_GetMHandle MAC + Tool $160F + <<< +~SetBarColors MAC + PxW ]1;]2;]3 +_SetBarColors MAC + Tool $170F + <<< +~GetBarColors MAC + PHS 2 +_GetBarColors MAC + Tool $180F + <<< +~SetMTitleStart MAC + PHW ]1 +_SetMTitleStart MAC + Tool $190F + <<< +~GetMTitleStart MAC + PHA +_GetMTitleStart MAC + Tool $1A0F + <<< +~GetMenuMgrPort MAC + PHS 2 +_GetMenuMgrPort MAC + Tool $1B0F + <<< +~CalcMenuSize MAC + PxW ]1;]2;]3 +_CalcMenuSize MAC + Tool $1C0F + <<< +~SetMTitleWidth MAC + PxW ]1;]2 +_SetMTitleWidth MAC + Tool $1D0F + <<< +~GetMTitleWidth MAC + P1SW ]1 +_GetMTitleWidth MAC + Tool $1E0F + <<< +~SetMenuFlag MAC + PxW ]1;]2 +_SetMenuFlag MAC + Tool $1F0F + <<< +~GetMenuFlag MAC + P1SW ]1 +_GetMenuFlag MAC + Tool $200F + <<< +~SetMenuTitle MAC + PHLW ]1;]2 +_SetMenuTitle MAC + Tool $210F + <<< +~GetMenuTitle MAC + P2SW ]1 +_GetMenuTitle MAC + Tool $220F + <<< +~MenuGlobal MAC + P1SW ]1 +_MenuGlobal MAC + Tool $230F + <<< +~SetMItem MAC + PHLW ]1;]2 +_SetMItem MAC + Tool $240F + <<< +~GetMItem MAC + PHLW ]1;]2 +_GetMItem MAC + Tool $250F + <<< +~SetMItemFlag MAC + PxW ]1;]2 +_SetMItemFlag MAC + Tool $260F + <<< +~GetMItemFlag MAC + P1SW ]1 +_GetMItemFlag MAC + Tool $270F + <<< +~SetMItemBlink MAC + PHW ]1 +_SetMItemBlink MAC + Tool $280F + <<< +_MenuNewRes MAC + Tool $290F + <<< +_DrawMenuBar MAC + Tool $2A0F + <<< +~MenuSelect MAC + PxL ]1;]2 +_MenuSelect MAC + Tool $2B0F + <<< +~HiliteMenu MAC + PxW ]1;]2 +_HiliteMenu MAC + Tool $2C0F + <<< +~NewMenu MAC + P2SL ]1 +_NewMenu MAC + Tool $2D0F + <<< +~DisposeMenu MAC + PHL ]1 +_DisposeMenu MAC + Tool $2E0F + <<< +_InitPalette MAC + Tool $2F0F + <<< +~EnableMItem MAC + PHW ]1 +_EnableMItem MAC + Tool $300F + <<< +~DisableMItem MAC + PHW ]1 +_DisableMItem MAC + Tool $310F + <<< +~CheckMItem MAC + PxW ]1;]2 +_CheckMItem MAC + Tool $320F + <<< +~SetMItemMark MAC + PxW ]1;]2 +_SetMItemMark MAC + Tool $330F + <<< +~GetMItemMark MAC + P1SW ]1 +_GetMItemMark MAC + Tool $340F + <<< +~SetMItemStyle MAC + PxW ]1;]2 +_SetMItemStyle MAC + Tool $350F + <<< +~GetMItemStyle MAC + P1SW ]1 +_GetMItemStyle MAC + Tool $360F + <<< +~SetMenuID MAC + PxW ]1;]2 +_SetMenuID MAC + Tool $370F + <<< +~SetMItemID MAC + PxW ]1;]2 +_SetMItemID MAC + Tool $380F + <<< +~SetMenuBar MAC + PHL ]1 +_SetMenuBar MAC + Tool $390F + <<< +~SetMItemName MAC + PHLW ]1;]2 +_SetMItemName MAC + Tool $3A0F + <<< +~GetPopUpDefProc MAC + PHS 2 +_GetPopUpDefProc MAC + Tool $3B0F + <<< +~PopUpMenuSelect MAC + PHA + PxW ]1;]2;]3;]4 + PHL ]5 +_PopUpMenuSelect MAC + Tool $3C0F + <<< +~DrawPopUp MAC + PxW ]1;]2;]3;]4 + PxW ]5;]6;]7 +_DrawPopUp MAC + Tool $3D0F + <<< +~NewMenu2 MAC + P2SW ]1 + PHL ]2 +_NewMenu2 MAC + Tool $3E0F + <<< +~InsertMItem2 MAC + PHWL ]1;]2 + PxW ]3;]4 +_InsertMItem2 MAC + Tool $3F0F + <<< +~SetMenuTitle2 MAC + PHWL ]1;]2 + PHW ]3 +_SetMenuTitle2 MAC + Tool $400F + <<< +~SetMItem2 MAC + PHWL ]1;]2 + PHW ]3 +_SetMItem2 MAC + Tool $410F + <<< +~SetMItemName2 MAC + PHWL ]1;]2 + PHW ]3 +_SetMItemName2 MAC + Tool $420F + <<< +~NewMenuBar2 MAC + P2SW ]1 + PxL ]2;]3 +_NewMenuBar2 MAC + Tool $430F + <<< +_HideMenuBar MAC + Tool $450F + <<< +_ShowMenuBar MAC + Tool $460F + <<< +_SetMItemIcon MAC + Tool $470F + <<< +_GetMItemIcon MAC + Tool $480F + <<< +_SetMItemStruct MAC + Tool $490F + <<< +_GetMItemStruct MAC + Tool $4A0F + <<< +_RemoveMItemStruct MAC + Tool $4B0F + <<< +_GetMItemFlag2 MAC + Tool $4C0F + <<< +_SetMItemFlag2 MAC + Tool $4D0F + <<< +_GetMItemBlink MAC + Tool $4F0F + <<< +_InsertPathMItems MAC + Tool $500F + <<< +~qMenuStartUp MAC + PHW ]1 + NextDP ]2;$100 + Tool $20F + <<< +~qNewMenu MAC + ~NewMenu ]1 + PHW #0 + _InsertMenu + <<< + diff --git a/Library/Midi.Macs.s b/Library/Midi.Macs.s new file mode 100644 index 0000000..15d0bb8 --- /dev/null +++ b/Library/Midi.Macs.s @@ -0,0 +1,79 @@ +* MIDI tool macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; + +_MidiBootInit MAC + Tool $120 + <<< +~MidiStartUp MAC + PxW ]1;]2 +_MidiStartUp MAC + Tool $220 + <<< +_MidiShutDown MAC + Tool $320 + <<< +~MidiVersion MAC + PHA +_MidiVersion MAC + Tool $420 + <<< +_MidiReset MAC + Tool $520 + <<< +~MidiStatus MAC + PHA +_MidiStatus MAC + Tool $620 + <<< +~MidiControl MAC + PHWL ]1;]2 +_MidiControl MAC + Tool $920 + <<< +~MidiDevice MAC + PHWL ]1;]2 +_MidiDevice MAC + Tool $A20 + <<< +~MidiClock MAC + PHWL ]1;]2 +_MidiClock MAC + Tool $B20 + <<< +~MidiInfo MAC + P2SW ]1 +_MidiInfo MAC + Tool $C20 + <<< +~MidiReadPacket MAC + P1SL ]1 + PHW ]2 +_MidiReadPacket MAC + Tool $D20 + <<< +~MidiWritePacket MAC + P1SL ]1 +_MidiWritePacket MAC + Tool $E20 + <<< +_MidiRecordSeq MAC + Tool $F20 + <<< +_MidiStopRecord MAC + Tool $1020 + <<< +_MidiPlaySeq MAC + Tool $1120 + <<< +_MidiStopPlay MAC + Tool $1220 + <<< +_MidiConvert MAC + Tool $1320 + <<< + diff --git a/Library/MidiSyn.Macs.s b/Library/MidiSyn.Macs.s new file mode 100644 index 0000000..4f862ac --- /dev/null +++ b/Library/MidiSyn.Macs.s @@ -0,0 +1,119 @@ +* +* Midi Synth tool calls +* + +_MSBootInit mac + Tool $0123 + <<< +_MSStartUp mac + Tool $0223 + <<< +_MSShutDown mac + Tool $0323 + <<< +_MSVersion mac + Tool $0423 + <<< +_MSReset mac + Tool $0523 + <<< +_MSStatus mac + Tool $0623 + <<< +_SetBasicChannel mac + Tool $0923 + <<< +_SetMIDIMode mac + Tool $0a23 + <<< +_PlayNote mac + Tool $0b23 + <<< +_StopNote mac + Tool $0c23 + <<< +_KillAllNotes mac + Tool $0d23 + <<< +_SetRecTrack mac + Tool $0e23 + <<< +_SetPlayTrack mac + Tool $0f23 + <<< +_TrackToChannel mac + Tool $1023 + <<< +_Locate mac + Tool $1123 + <<< +_SetVelComp mac + Tool $1223 + <<< +_SetMIDIPort mac + Tool $1323 + <<< +_SetInstrument mac + Tool $1423 + <<< +_SeqPlayer mac + Tool $1523 + <<< +_SetTempo mac + Tool $1623 + <<< +_SetCallBack mac + Tool $1723 + <<< +_SysExOut mac + Tool $1823 + <<< +_SetBeat mac + Tool $1923 + <<< +_MIDIMessage mac + Tool $1a23 + <<< +_LocateEnd mac + Tool $1b23 + <<< +_Merge mac + Tool $1c23 + <<< +_DeleteTrack mac + Tool $1d23 + <<< +_SetMetro mac + Tool $1e23 + <<< +_GetMSData mac + Tool $1f23 + <<< +_ConvertToTime mac + Tool $2023 + <<< +_ConvertToMeasure mac + Tool $2123 + <<< +_MSSuspend mac + Tool $2223 + <<< +_MSResume mac + Tool $2323 + <<< +_SetTuningTable mac + Tool $2423 + <<< +_GetTuningTable mac + Tool $2523 + <<< +_SetTrackOut mac + Tool $2623 + <<< +_InitMIDIDriver mac + Tool $2723 + <<< +_RemoveMIDIDriver mac + Tool $2823 + <<< + diff --git a/Library/Misc.Macs.s b/Library/Misc.Macs.s new file mode 100644 index 0000000..d562d8b --- /dev/null +++ b/Library/Misc.Macs.s @@ -0,0 +1,278 @@ +* Misc Tool macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_MTBootInit MAC + Tool $103 + <<< +_MTStartUp MAC + Tool $203 + <<< +_MTShutDown MAC + Tool $303 + <<< +~MTVersion MAC + PHA +_MTVersion MAC + Tool $403 + <<< +_MTReset MAC + Tool $503 + <<< +~MTStatus MAC + PHA +_MTStatus MAC + Tool $603 + <<< +~WriteBRam MAC + PHL ]1 +_WriteBRam MAC + Tool $903 + <<< +~ReadBRam MAC + PHL ]1 +_ReadBRam MAC + Tool $A03 + <<< +~WriteBParam MAC + PxW ]1;]2 +_WriteBParam MAC + Tool $B03 + <<< +~ReadBParam MAC + P1SW ]1 +_ReadBParam MAC + Tool $C03 + <<< +~ReadTimeHex MAC + PHS 4 +_ReadTimeHex MAC + Tool $D03 + <<< +~WriteTimeHex MAC + PxW ]1;]2;]3 +_WriteTimeHex MAC + Tool $E03 + <<< +~ReadAsciiTime MAC + PHL ]1 +_ReadAsciiTime MAC + Tool $F03 + <<< +~SetVector MAC + PHWL ]1;]2 +_SetVector MAC + Tool $1003 + <<< +~GetVector MAC + P2SW ]1 +_GetVector MAC + Tool $1103 + <<< +~SetHeartBeat MAC + PHL ]1 +_SetHeartBeat MAC + Tool $1203 + <<< +~DelHeartBeat MAC + PHL ]1 +_DelHeartBeat MAC + Tool $1303 + <<< +_ClrHeartBeat MAC + Tool $1403 + <<< +~SysFailMgr MAC + PHWL ]1;]2 +_SysFailMgr MAC + Tool $1503 + <<< +~GetAddr MAC + P2SW ]1 +_GetAddr MAC + Tool $1603 + <<< +~ReadMouse MAC + PHS 3 +_ReadMouse MAC + Tool $1703 + <<< +~InitMouse MAC + PHW ]1 +_InitMouse MAC + Tool $1803 + <<< +~SetMouse MAC + PHW ]1 +_SetMouse MAC + Tool $1903 + <<< +_HomeMouse MAC + Tool $1A03 + <<< +_ClearMouse MAC + Tool $1B03 + <<< +~ClampMouse MAC + PxW ]1;]2;]3;]4 +_ClampMouse MAC + Tool $1C03 + <<< +~GetMouseClamp MAC + PHS 4 +_GetMouseClamp MAC + Tool $1D03 + <<< +~PosMouse MAC + PxW ]1;]2 +_PosMouse MAC + Tool $1E03 + <<< +~ServeMouse MAC + PHA +_ServeMouse MAC + Tool $1F03 + <<< +~GetNewID MAC + P1SW ]1 +_GetNewID MAC + Tool $2003 + <<< +~DeleteID MAC + PHW ]1 +_DeleteID MAC + Tool $2103 + <<< +~StatusID MAC + PHW ]1 +_StatusID MAC + Tool $2203 + <<< +~IntSource MAC + PHW ]1 +_IntSource MAC + Tool $2303 + <<< +~FWEntry MAC + PHS 4 + PxW ]1;]2;]3;]4 +_FWEntry MAC + Tool $2403 + <<< +~GetTick MAC + PHS 2 +_GetTick MAC + Tool $2503 + <<< +~PackBytes MAC + P1SL ]1 + PxL ]2;]3 + PHW ]4 +_PackBytes MAC + Tool $2603 + <<< +~UnPackBytes MAC + P1SL ]1 + PHW ]2 + PxL ]3;]4 +_UnPackBytes MAC + Tool $2703 + <<< +~Munger MAC + P1SL ]1 + PxL ]2;]3 + PHWL ]4;]5 + PHWL ]6;]7 +_Munger MAC + Tool $2803 + <<< +~GetIRQEnable MAC + PHA +_GetIRQEnable MAC + Tool $2903 + <<< +~SetAbsClamp MAC + PxW ]1;]2;]3;]4 +_SetAbsClamp MAC + Tool $2A03 + <<< +~GetAbsClamp MAC + PHS 4 +_GetAbsClamp MAC + Tool $2B03 + <<< +_SysBeep MAC + Tool $2C03 + <<< +~AddToQueue MAC + PxL ]1;]2 +_AddToQueue MAC + Tool $2E03 + <<< +~DeleteFromQueue MAC + PxL ]1;]2 +_DeleteFromQueue MAC + Tool $2F03 + <<< +~SetInterruptState MAC + PHLW ]1;]2 +_SetInterruptState MAC + Tool $3003 + <<< +~GetInterruptState MAC + PHLW ]1;]2 +_GetInterruptState MAC + Tool $3103 + <<< +~GetIntStateRecSize MAC + PHA +_GetIntStateRecSize MAC + Tool $3203 + <<< +~ReadMouse2 MAC + PHS 3 +_ReadMouse2 MAC + Tool $3303 + <<< +~GetCodeResConverter MAC + PHS 2 +_GetCodeResConverter MAC + Tool $3403 + <<< +_GetROMResource MAC ;private + Tool $3503 + <<< +_ReleaseROMResource MAC ;private + Tool $3603 + <<< +_ConvSeconds MAC + Tool $3703 + <<< +_SysBeep2 MAC + Tool $3803 + <<< +_VersionString MAC + Tool $3903 + <<< +_WaitUntil MAC + Tool $3A03 + <<< +_StringToText MAC + Tool $3B03 + <<< +_ShowBootInfo MAC + Tool $3C03 + <<< +_ScanDevices MAC + Tool $3D03 + <<< +_AlertMessage MAC + Tool $3E03 + <<< +_DoSysPrefs MAC + Tool $3F03 + <<< + diff --git a/Library/NoteSeq.Macs.s b/Library/NoteSeq.Macs.s new file mode 100644 index 0000000..e08e44e --- /dev/null +++ b/Library/NoteSeq.Macs.s @@ -0,0 +1,89 @@ +* Note sequencer macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_SeqBootInit MAC + Tool $011A + <<< +~SeqStartUp MAC + PxW ]1;]2;]3;]4 +_SeqStartUp MAC + Tool $021A + <<< +_SeqShutDown MAC + Tool $031A + <<< +~SeqVersion MAC + PHA +_SeqVersion MAC + Tool $041A + <<< +_SeqReset MAC + Tool $051A + <<< +~SeqStatus MAC + PHA +_SeqStatus MAC + Tool $061A + <<< +~SetIncr MAC + PHW ]1 +_SetIncr MAC + Tool $091A + <<< +~ClearIncr MAC + PHA +_ClearIncr MAC + Tool $0A1A + <<< +~GetTimer MAC + PHA +_GetTimer MAC + Tool $0B1A + <<< +~GetLoc MAC + PHS 3 +_GetLoc MAC + Tool $0C1A + <<< +_SeqAllNotesOff MAC + Tool $0D1A + <<< +~SetTrkInfo MAC + PxW ]1;]2;]3 +_SetTrkInfo MAC + Tool $0E1A + <<< +~StartSeq MAC + PxL ]1;]2;]3 +_StartSeq MAC + Tool $0F1A + <<< +_StepSeq MAC + Tool $101A + <<< +~StopSeq MAC + PHW ]1 +_StopSeq MAC + Tool $111A + <<< +~SetInstTable MAC + PHL ]1 +_SetInstTable MAC + Tool $121A + <<< +_StartInts MAC + Tool $131A + <<< +_StopInts MAC + Tool $141A + <<< +~StartSeqRel MAC + PxL ]1;]2;]3 +_StartSeqRel MAC + Tool $151A + <<< + diff --git a/Library/NoteSyn.Macs.s b/Library/NoteSyn.Macs.s new file mode 100644 index 0000000..a74a0d9 --- /dev/null +++ b/Library/NoteSyn.Macs.s @@ -0,0 +1,66 @@ +* Note synthesizer macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_NSBootInit MAC + Tool $119 + <<< +~NSStartUp MAC + PHWL ]1;]2 +_NSStartUp MAC + Tool $219 + <<< +_NSShutDown MAC + Tool $319 + <<< +~NSVersion MAC + PHA +_NSVersion MAC + Tool $419 + <<< +_NSReset MAC + Tool $519 + <<< +~NSStatus MAC + PHA +_NSStatus MAC + Tool $619 + <<< +~AllocGen MAC + P1SW ]1 +_AllocGen MAC + Tool $919 + <<< +~DeallocGen MAC + PHW ]1 +_DeallocGen MAC + Tool $A19 + <<< +~NoteOn MAC + PxW ]1;]2;]3 + PHL ]4 +_NoteOn MAC + Tool $B19 + <<< +~NoteOff MAC + PxW ]1;]2 +_NoteOff MAC + Tool $C19 + <<< +_AllNotesOff MAC + Tool $D19 + <<< +~NSSetUpdateRate MAC + P1SW ]1 +_NSSetUpdateRate MAC + Tool $E19 + <<< +~NSSetUserUpdateRtn MAC + P2SL ]1 +_NSSetUserUpdateRtn MAC + Tool $F19 + <<< + diff --git a/Library/Print.Macs.s b/Library/Print.Macs.s new file mode 100644 index 0000000..a310375 --- /dev/null +++ b/Library/Print.Macs.s @@ -0,0 +1,220 @@ +* Print Mgr. macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_PMBootInit MAC + Tool $0113 + <<< +~PMStartUp MAC + PxW ]1;]2 +_PMStartUp MAC + Tool $0213 + <<< +_PMShutDown MAC + Tool $0313 + <<< +~PMVersion MAC + PHA +_PMVersion MAC + Tool $0413 + <<< +_PMReset MAC + Tool $0513 + <<< +~PMStatus MAC + PHA +_PMStatus MAC + Tool $0613 + <<< +~PrDefault MAC + PHL ]1 +_PrDefault MAC + Tool $0913 + <<< +~PrValidate MAC + P1SL ]1 +_PrValidate MAC + Tool $0A13 + <<< +~PrStlDialog MAC + P1SL ]1 +_PrStlDialog MAC + Tool $0B13 + <<< +~PrJobDialog MAC + P1SL ]1 +_PrJobDialog MAC + Tool $0C13 + <<< +~PrPixelMap MAC + PxL ]1;]2 + PHW ]3 +_PrPixelMap MAC + Tool $0D13 + <<< +~PrOpenDoc MAC + P2SL ]1 + PHL ]2 +_PrOpenDoc MAC + Tool $0E13 + <<< +~PrCloseDoc MAC + PHL ]1 +_PrCloseDoc MAC + Tool $0F13 + <<< +~PrOpenPage MAC + PxL ]1;]2 +_PrOpenPage MAC + Tool $1013 + <<< +~PrClosePage MAC + PHL ]1 +_PrClosePage MAC + Tool $1113 + <<< +~PrPicFile MAC + PxL ]1;]2;]3 +_PrPicFile MAC + Tool $1213 + <<< +_PrControl MAC + Tool $1313 + <<< +~PrError MAC + PHA +_PrError MAC + Tool $1413 + <<< +~PrSetError MAC + PHW ]1 +_PrSetError MAC + Tool $1513 + <<< +~PrChoosePrinter MAC + PHA +_PrChoosePrinter MAC + Tool $1613 + <<< +_GetDeviceName MAC + Tool $1703 + <<< +~PrGetPrinterSpecs MAC + PHS 2 +_PrGetPrinterSpecs MAC + Tool $1813 + <<< +_PrDevPrChanged MAC + Tool $1913 + <<< +_PrDevStartup MAC + Tool $1A13 + <<< +_PrDevShutDown MAC + Tool $1B13 + <<< +_PrDevOpen MAC + Tool $1C13 + <<< +_PrDevRead MAC + Tool $1D13 + <<< +_PrDevWrite MAC + Tool $1E13 + <<< +_PrDevClose MAC + Tool $1F13 + <<< +_PrDevStatus MAC + Tool $2013 + <<< +_PrDevAsyncRead MAC + Tool $2113 + <<< +_PrDevWriteBackground MAC + Tool $2213 + <<< +~PrDriverVer MAC + PHA +_PrDriverVer MAC + Tool $2313 + <<< +~PrPortVer MAC + PHA +_PrPortVer MAC + Tool $2413 + <<< +~PrGetZoneName MAC + PHS 2 +_PrGetZoneName MAC + Tool $2513 + <<< +~PrGetPrinterDvrName MAC + PHS 2 +_PrGetPrinterDvrName MAC + Tool $2813 + <<< +~PrGetPortDvrName MAC + PHS 2 +_PrGetPortDvrName MAC + Tool $2913 + <<< +~PrGetUserName MAC + PHS 2 +_PrGetUserName MAC + Tool $2A13 + <<< +~PrGetNetworkName MAC + PHS 2 +_PrGetNetworkName MAC + Tool $2B13 + <<< +_PrDevIsItSafe MAC + Tool $3013 + <<< +_GetZoneList MAC + Tool $3113 + <<< +_GetMyZone MAC + Tool $3213 + <<< +_GetPrinterList MAC + Tool $3313 + <<< +~PMUnloadDriver MAC + PHW ]1 +_PMUnloadDriver MAC + Tool $3413 + <<< +~PMLoadDriver MAC + PHW ]1 +_PMLoadDriver MAC + Tool $3513 + <<< +~PrGetDocName MAC + PHS 2 +_PrGetDocName MAC + Tool $3613 + <<< +~PrSetDocName MAC + PHL ]1 +_PrSetDocName MAC + Tool $3713 + <<< +~PrGetPgOrientation MAC + P1SL ]1 +_PrGetPgOrientation MAC + Tool $3813 + <<< +~qPMStartUp MAC + PHW ]1 + CLC + LDA ]2 + ADC ]NextDP + PHA + Tool $0213 + <<< + diff --git a/Library/Qd.Macs.s b/Library/Qd.Macs.s new file mode 100644 index 0000000..d311e76 --- /dev/null +++ b/Library/Qd.Macs.s @@ -0,0 +1,1102 @@ +* QuickDraw II macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_QDBootInit MAC + Tool $104 + <<< +~QDStartUp MAC + PxW ]1;]2;]3;]4 +_QDStartUp MAC + Tool $204 + <<< +_QDShutDown MAC + Tool $304 + <<< +~QDVersion MAC + PHA +_QDVersion MAC + Tool $404 + <<< +_QDReset MAC + Tool $504 + <<< +~QDStatus MAC + PHA +_QDStatus MAC + Tool $604 + <<< +~GetAddress MAC + P2SW ]1 +_GetAddress MAC + Tool $904 + <<< +_GrafOn MAC + Tool $A04 + <<< +_GrafOff MAC + Tool $B04 + <<< +~GetStandardSCB MAC + PHA +_GetStandardSCB MAC + Tool $C04 + <<< +~InitColorTable MAC + PHL ]1 +_InitColorTable MAC + Tool $D04 + <<< +~SetColorTable MAC + PHWL ]1;]2 +_SetColorTable MAC + Tool $E04 + <<< +~GetColorTable MAC + PHWL ]1;]2 +_GetColorTable MAC + Tool $F04 + <<< +~SetColorEntry MAC + PxW ]1;]2;]3 +_SetColorEntry MAC + Tool $1004 + <<< +~GetColorEntry MAC + PHA + PxW ]1;]2 +_GetColorEntry MAC + Tool $1104 + <<< +~SetSCB MAC + PxW ]1;]2 +_SetSCB MAC + Tool $1204 + <<< +~GetSCB MAC + P1SW ]1 +_GetSCB MAC + Tool $1304 + <<< +~SetAllSCBs MAC + PHW ]1 +_SetAllSCBs MAC + Tool $1404 + <<< +~ClearScreen MAC + PHW ]1 +_ClearScreen MAC + Tool $1504 + <<< +~SetMasterSCB MAC + PHW ]1 +_SetMasterSCB MAC + Tool $1604 + <<< +~GetMasterSCB MAC + PHA +_GetMasterSCB MAC + Tool $1704 + <<< +~OpenPort MAC + PHL ]1 +_OpenPort MAC + Tool $1804 + <<< +~InitPort MAC + PHL ]1 +_InitPort MAC + Tool $1904 + <<< +~ClosePort MAC + PHL ]1 +_ClosePort MAC + Tool $1A04 + <<< +~SetPort MAC + PHL ]1 +_SetPort MAC + Tool $1B04 + <<< +~GetPort MAC + PHS 2 +_GetPort MAC + Tool $1C04 + <<< +~SetPortLoc MAC + PHL ]1 +_SetPortLoc MAC + Tool $1D04 + <<< +~GetPortLoc MAC + PHL ]1 +_GetPortLoc MAC + Tool $1E04 + <<< +~SetPortRect MAC + PHL ]1 +_SetPortRect MAC + Tool $1F04 + <<< +~GetPortRect MAC + PHL ]1 +_GetPortRect MAC + Tool $2004 + <<< +~SetPortSize MAC + PxW ]1;]2 +_SetPortSize MAC + Tool $2104 + <<< +~MovePortTo MAC + PxW ]1;]2 +_MovePortTo MAC + Tool $2204 + <<< +~SetOrigin MAC + PxW ]1;]2 +_SetOrigin MAC + Tool $2304 + <<< +~SetClip MAC + PHL ]1 +_SetClip MAC + Tool $2404 + <<< +~GetClip MAC + PHL ]1 +_GetClip MAC + Tool $2504 + <<< +~ClipRect MAC + PHL ]1 +_ClipRect MAC + Tool $2604 + <<< +_HidePen MAC + Tool $2704 + <<< +_ShowPen MAC + Tool $2804 + <<< +~GetPen MAC + PHL ]1 +_GetPen MAC + Tool $2904 + <<< +~SetPenState MAC + PHL ]1 +_SetPenState MAC + Tool $2A04 + <<< +~GetPenState MAC + PHL ]1 +_GetPenState MAC + Tool $2B04 + <<< +~SetPenSize MAC + PxW ]1;]2 +_SetPenSize MAC + Tool $2C04 + <<< +~GetPenSize MAC + PHL ]1 +_GetPenSize MAC + Tool $2D04 + <<< +~SetPenMode MAC + PHW ]1 +_SetPenMode MAC + Tool $2E04 + <<< +~GetPenMode MAC + PHA +_GetPenMode MAC + Tool $2F04 + <<< +~SetPenPat MAC + PHL ]1 +_SetPenPat MAC + Tool $3004 + <<< +~GetPenPat MAC + PHL ]1 +_GetPenPat MAC + Tool $3104 + <<< +~SetPenMask MAC + PHL ]1 +_SetPenMask MAC + Tool $3204 + <<< +~GetPenMask MAC + PHL ]1 +_GetPenMask MAC + Tool $3304 + <<< +~SetBackPat MAC + PHL ]1 +_SetBackPat MAC + Tool $3404 + <<< +~GetBackPat MAC + PHL ]1 +_GetBackPat MAC + Tool $3504 + <<< +_PenNormal MAC + Tool $3604 + <<< +~SetSolidPenPat MAC + PHW ]1 +_SetSolidPenPat MAC + Tool $3704 + <<< +~SetSolidBackPat MAC + PHW ]1 +_SetSolidBackPat MAC + Tool $3804 + <<< +~SolidPattern MAC + PHWL ]1;]2 +_SolidPattern MAC + Tool $3904 + <<< +~MoveTo MAC +GotoXY MAC +QDGotoXY MAC + PxW ]1;]2 +_MoveTo MAC + Tool $3A04 + <<< +~Move MAC + PxW ]1;]2 +_Move MAC + Tool $3B04 + <<< +~LineTo MAC + PxW ]1;]2 +_LineTo MAC + Tool $3C04 + <<< +~Line MAC + PxW ]1;]2 +_Line MAC + Tool $3D04 + <<< +~SetPicSave MAC + PHL ]1 +_SetPicSave MAC + Tool $3E04 + <<< +~GetPicSave MAC + PHS 2 +_GetPicSave MAC + Tool $3F04 + <<< +~SetRgnSave MAC + PHL ]1 +_SetRgnSave MAC + Tool $4004 + <<< +~GetRgnSave MAC + PHS 2 +_GetRgnSave MAC + Tool $4104 + <<< +~SetPolySave MAC + PHL ]1 +_SetPolySave MAC + Tool $4204 + <<< +~GetPolySave MAC + PHS 2 +_GetPolySave MAC + Tool $4304 + <<< +~SetGrafProcs MAC + PHL ]1 +_SetGrafProcs MAC + Tool $4404 + <<< +~GetGrafProcs MAC + PHS 2 +_GetGrafProcs MAC + Tool $4504 + <<< +~SetUserField MAC + PHL ]1 +_SetUserField MAC + Tool $4604 + <<< +~GetUserField MAC + PHS 2 +_GetUserField MAC + Tool $4704 + <<< +~SetSysField MAC + PHL ]1 +_SetSysField MAC + Tool $4804 + <<< +~GetSysField MAC + PHS 2 +_GetSysField MAC + Tool $4904 + <<< +~SetRect MAC + PHL ]1 + PxW ]2;]3;]4;]5 +_SetRect MAC + Tool $4A04 + <<< +~OffsetRect MAC + PHL ]1 + PxW ]2;]3 +_OffsetRect MAC + Tool $4B04 + <<< +~InsetRect MAC + PHL ]1 + PxW ]2;]3 +_InsetRect MAC + Tool $4C04 + <<< +~SectRect MAC + PHA + PxL ]1;]2;]3 +_SectRect MAC + Tool $4D04 + <<< +~UnionRect MAC + PxL ]1;]2;]3 +_UnionRect MAC + Tool $4E04 + <<< +~PtInRect MAC + PHA + PxL ]1;]2 +_PtInRect MAC + Tool $4F04 + <<< +~Pt2Rect MAC + PxL ]1;]2;]3 +_Pt2Rect MAC + Tool $5004 + <<< +~EqualRect MAC + PHA + PxL ]1;]2 +_EqualRect MAC + Tool $5104 + <<< +~NotEmptyRect MAC + P1SL ]1 +_NotEmptyRect MAC + Tool $5204 + <<< +~EmptyRect MAC + P1SL ]1 +_EmptyRect MAC + Tool $5204 + <<< +~FrameRect MAC + PHL ]1 +_FrameRect MAC + Tool $5304 + <<< +~PaintRect MAC + PHL ]1 +_PaintRect MAC + Tool $5404 + <<< +~EraseRect MAC + PHL ]1 +_EraseRect MAC + Tool $5504 + <<< +~InvertRect MAC + PHL ]1 +_InvertRect MAC + Tool $5604 + <<< +~FillRect MAC + PxL ]1;]2 +_FillRect MAC + Tool $5704 + <<< +~FrameOval MAC + PHL ]1 +_FrameOval MAC + Tool $5804 + <<< +~PaintOval MAC + PHL ]1 +_PaintOval MAC + Tool $5904 + <<< +~EraseOval MAC + PHL ]1 +_EraseOval MAC + Tool $5A04 + <<< +~InvertOval MAC + PHL ]1 +_InvertOval MAC + Tool $5B04 + <<< +~FillOval MAC + PxL ]1;]2 +_FillOval MAC + Tool $5C04 + <<< +~FrameRRect MAC + PHL ]1 + PxW ]2;]3 +_FrameRRect MAC + Tool $5D04 + <<< +~PaintRRect MAC + PHL ]1 + PxW ]2;]3 +_PaintRRect MAC + Tool $5E04 + <<< +~EraseRRect MAC + PHL ]1 + PxW ]2;]3 +_EraseRRect MAC + Tool $5F04 + <<< +~InvertRRect MAC + PHL ]1 + PxW ]2;]3 +_InvertRRect MAC + Tool $6004 + <<< +~FillRRect MAC + PHLW ]1;]2 + PHWL ]3;]4 +_FillRRect MAC + Tool $6104 + <<< +~FrameArc MAC + PHL ]1 + PxW ]2;]3 +_FrameArc MAC + Tool $6204 + <<< +~PaintArc MAC + PHL ]1 + PxW ]2;]3 +_PaintArc MAC + Tool $6304 + <<< +~EraseArc MAC + PHL ]1 + PxW ]2;]3 +_EraseArc MAC + Tool $6404 + <<< +~InvertArc MAC + PHL ]1 + PxW ]2;]3 +_InvertArc MAC + Tool $6504 + <<< +~FillArc MAC + PHLW ]1;]2 + PHWL ]3;]4 +_FillArc MAC + Tool $6604 + <<< +~NewRgn MAC + PHS 2 +_NewRgn MAC + Tool $6704 + <<< +~DisposeRgn MAC + PHL ]1 +_DisposeRgn MAC + Tool $6804 + <<< +~CopyRgn MAC + PxL ]1;]2 +_CopyRgn MAC + Tool $6904 + <<< +~SetEmptyRgn MAC + PHL ]1 +_SetEmptyRgn MAC + Tool $6A04 + <<< +~SetRectRgn MAC + PHL ]1 + PxW ]2;]3;]4;]5 +_SetRectRgn MAC + Tool $6B04 + <<< +~RectRgn MAC + PxL ]1;]2 +_RectRgn MAC + Tool $6C04 + <<< +_OpenRgn MAC + Tool $6D04 + <<< +~CloseRgn MAC + PHL ]1 +_CloseRgn MAC + Tool $6E04 + <<< +~OffsetRgn MAC + PHL ]1 + PxW ]2;]3 +_OffsetRgn MAC + Tool $6F04 + <<< +~InsetRgn MAC + PHL ]1 + PxW ]2;]3 +_InsetRgn MAC + Tool $7004 + <<< +~SectRgn MAC + PxL ]1;]2;]3 +_SectRgn MAC + Tool $7104 + <<< +~UnionRgn MAC + PxL ]1;]2;]3 +_UnionRgn MAC + Tool $7204 + <<< +~DiffRgn MAC + PxL ]1;]2;]3 +_DiffRgn MAC + Tool $7304 + <<< +~XorRgn MAC + PxL ]1;]2;]3 +_XorRgn MAC + Tool $7404 + <<< +~PtInRgn MAC + PHA + PxL ]1;]2 +_PtInRgn MAC + Tool $7504 + <<< +~RectInRgn MAC + PHA + PxL ]1;]2 +_RectInRgn MAC + Tool $7604 + <<< +~EqualRgn MAC + PHA + PxL ]1;]2 +_EqualRgn MAC + Tool $7704 + <<< +~EmptyRgn MAC + P1SL ]1 +_EmptyRgn MAC + Tool $7804 + <<< +~FrameRgn MAC + PHL ]1 +_FrameRgn MAC + Tool $7904 + <<< +~PaintRgn MAC + PHL ]1 +_PaintRgn MAC + Tool $7A04 + <<< +~EraseRgn MAC + PHL ]1 +_EraseRgn MAC + Tool $7B04 + <<< +~InvertRgn MAC + PHL ]1 +_InvertRgn MAC + Tool $7C04 + <<< +~FillRgn MAC + PxL ]1;]2 +_FillRgn MAC + Tool $7D04 + <<< +~ScrollRect MAC + PHLW ]1;]2 + PHWL ]3;]4 +_ScrollRect MAC + Tool $7E04 + <<< +~PaintPixels MAC + PHL ]1 +_PaintPixels MAC + Tool $7F04 + <<< +~AddPt MAC + PxL ]1;]2 +_AddPt MAC + Tool $8004 + <<< +~SubPt MAC + PxL ]1;]2 +_SubPt MAC + Tool $8104 + <<< +~SetPt MAC + PHL ]1 + PxW ]2;]3 +_SetPt MAC + Tool $8204 + <<< +~EqualPt MAC + PHA + PxL ]1;]2 +_EqualPt MAC + Tool $8304 + <<< +~LocalToGlobal MAC + PHL ]1 +_LocalToGlobal MAC + Tool $8404 + <<< +~GlobalToLocal MAC + PHL ]1 +_GlobalToLocal MAC + Tool $8504 + <<< +~Random MAC + PHA +_Random MAC + Tool $8604 + <<< +~SetRandSeed MAC + PHL ]1 +_SetRandSeed MAC + Tool $8704 + <<< +~GetPixel MAC + PHA + PxW ]1;]2 +_GetPixel MAC + Tool $8804 + <<< +~ScalePt MAC + PxL ]1;]2;]3 +_ScalePt MAC + Tool $8904 + <<< +~MapPt MAC + PxL ]1;]2;]3 +_MapPt MAC + Tool $8A04 + <<< +~MapRect MAC + PxL ]1;]2;]3 +_MapRect MAC + Tool $8B04 + <<< +~MapRgn MAC + PxL ]1;]2;]3 +_MapRgn MAC + Tool $8C04 + <<< +~SetStdProcs MAC + PHL ]1 +_SetStdProcs MAC + Tool $8D04 + <<< +~SetCursor MAC + PHL ]1 +_SetCursor MAC + Tool $8E04 + <<< +~GetCursorAdr MAC + PHS 2 +_GetCursorAdr MAC + Tool $8F04 + <<< +_HideCursor MAC + Tool $9004 + <<< +_ShowCursor MAC + Tool $9104 + <<< +_ObscureCursor MAC + Tool $9204 + <<< +_SetMouseLoc MAC + Tool $9304 + <<< +~SetFont MAC + PHL ]1 +_SetFont MAC + Tool $9404 + <<< +~GetFont MAC + PHS 2 +_GetFont MAC + Tool $9504 + <<< +~GetFontInfo MAC + PHL ]1 +_GetFontInfo MAC + Tool $9604 + <<< +~GetFontGlobals MAC + PHL ]1 +_GetFontGlobals MAC + Tool $9704 + <<< +~SetFontFlags MAC + PHW ]1 +_SetFontFlags MAC + Tool $9804 + <<< +~GetFontFlags MAC + PHA +_GetFontFlags MAC + Tool $9904 + <<< +~SetTextFace MAC + PHW ]1 +_SetTextFace MAC + Tool $9A04 + <<< +~GetTextFace MAC + PHA +_GetTextFace MAC + Tool $9B04 + <<< +~SetTextMode MAC + PHW ]1 +_SetTextMode MAC + Tool $9C04 + <<< +~GetTextMode MAC + PHA +_GetTextMode MAC + Tool $9D04 + <<< +~SetSpaceExtra MAC + PHL ]1 +_SetSpaceExtra MAC + Tool $9E04 + <<< +~GetSpaceExtra MAC + PHS 2 +_GetSpaceExtra MAC + Tool $9F04 + <<< +~SetForeColor MAC + PHW ]1 +_SetForeColor MAC + Tool $A004 + <<< +~GetForeColor MAC + PHA +_GetForeColor MAC + Tool $A104 + <<< +~SetBackColor MAC + PHW ]1 +_SetBackColor MAC + Tool $A204 + <<< +~GetBackColor MAC + PHA +_GetBackColor MAC + Tool $A304 + <<< +~DrawChar MAC + PHW ]1 +_DrawChar MAC + Tool $A404 + <<< +~DrawString MAC + PHL ]1 +_DrawString MAC + Tool $A504 + <<< +~DrawCString MAC + PHL ]1 +_DrawCString MAC + Tool $A604 + <<< +~DrawText MAC + PHLW ]1;]2 +_DrawText MAC + Tool $A704 + <<< +~CharWidth MAC + P1SW ]1 +_CharWidth MAC + Tool $A804 + <<< +~StringWidth MAC + P1SL ]1 +_StringWidth MAC + Tool $A904 + <<< +~CStringWidth MAC + P1SL ]1 +_CStringWidth MAC + Tool $AA04 + <<< +~TextWidth MAC + P1SL ]1 + PHW ]2 +_TextWidth MAC + Tool $AB04 + <<< +~CharBounds MAC + PHWL ]1;]2 +_CharBounds MAC + Tool $AC04 + <<< +~StringBounds MAC + PxL ]1;]2 +_StringBounds MAC + Tool $AD04 + <<< +~CStringBounds MAC + PxL ]1;]2 +_CStringBounds MAC + Tool $AE04 + <<< +~TextBounds MAC + PHLW ]1;]2 + PHL ]3 +_TextBounds MAC + Tool $AF04 + <<< +~SetArcRot MAC + PHW ]1 +_SetArcRot MAC + Tool $B004 + <<< +~GetArcRot MAC + PHA +_GetArcRot MAC + Tool $B104 + <<< +~SetSysFont MAC + PHL ]1 +_SetSysFont MAC + Tool $B204 + <<< +~GetSysFont MAC + PHS 2 +_GetSysFont MAC + Tool $B304 + <<< +~SetVisRgn MAC + PHL ]1 +_SetVisRgn MAC + Tool $B404 + <<< +~GetVisRgn MAC + PHL ]1 +_GetVisRgn MAC + Tool $B504 + <<< +~SetIntUse MAC + PHW ]1 +_SetIntUse MAC + Tool $B604 + <<< +~OpenPicture MAC + P2SL ]1 +_OpenPicture MAC + Tool $B704 + <<< +~PicComment MAC + PHW ]1 + PHWL ]2;]3 +_PicComment MAC + Tool $B804 + <<< +_ClosePicture MAC + Tool $B904 + <<< +~DrawPicture MAC + PxL ]1;]2 +_DrawPicture MAC + Tool $BA04 + <<< +~KillPicture MAC + PHL ]1 +_KillPicture MAC + Tool $BB04 + <<< +~FramePoly MAC + PHL ]1 +_FramePoly MAC + Tool $BC04 + <<< +~PaintPoly MAC + PHL ]1 +_PaintPoly MAC + Tool $BD04 + <<< +~ErasePoly MAC + PHL ]1 +_ErasePoly MAC + Tool $BE04 + <<< +~InvertPoly MAC + PHL ]1 +_InvertPoly MAC + Tool $BF04 + <<< +~FillPoly MAC + PxL ]1;]2 +_FillPoly MAC + Tool $C004 + <<< +~OpenPoly MAC + PHS 2 +_OpenPoly MAC + Tool $C104 + <<< +_ClosePoly MAC + Tool $C204 + <<< +~KillPoly MAC + PHL ]1 +_KillPoly MAC + Tool $C304 + <<< +~OffsetPoly MAC + PHL ]1 + PxW ]2;]3 +_OffsetPoly MAC + Tool $C404 + <<< +~MapPoly MAC + PxL ]1;]2;]3 +_MapPoly MAC + Tool $C504 + <<< +~SetClipHandle MAC + PHL ]1 +_SetClipHandle MAC + Tool $C604 + <<< +~GetClipHandle MAC + PHS 2 +_GetClipHandle MAC + Tool $C704 + <<< +~SetVisHandle MAC + PHL ]1 +_SetVisHandle MAC + Tool $C804 + <<< +~GetVisHandle MAC + PHS 2 +_GetVisHandle MAC + Tool $C904 + <<< +_InitCursor MAC + Tool $CA04 + <<< +~SetBufDims MAC + PxW ]1;]2;]3 +_SetBufDims MAC + Tool $CB04 + <<< +~ForceBufDims MAC + PxW ]1;]2;]3 +_ForceBufDims MAC + Tool $CC04 + <<< +~SaveBufDims MAC + PHL ]1 +_SaveBufDims MAC + Tool $CD04 + <<< +~RestoreBufDims MAC + PHL ]1 +_RestoreBufDims MAC + Tool $CE04 + <<< +~GetFGSize MAC + PHA +_GetFGSize MAC + Tool $CF04 + <<< +~SetFontID MAC + PHL ]1 +_SetFontID MAC + Tool $D004 + <<< +~GetFontID MAC + PHS 2 +_GetFontID MAC + Tool $D104 + <<< +~SetTextSize MAC + PHW ]1 +_SetTextSize MAC + Tool $D204 + <<< +~GetTextSize MAC + PHA +_GetTextSize MAC + Tool $D304 + <<< +~SetCharExtra MAC + PHL ]1 +_SetCharExtra MAC + Tool $D404 + <<< +~GetCharExtra MAC + PHS 2 +_GetCharExtra MAC + Tool $D504 + <<< +~PPToPort MAC + PxL ]1;]2 + PxW ]3;]4;]5 +_PPToPort MAC + Tool $D604 + <<< +~InflateTextBuffer MAC + PxW ]1;]2 +_InflateTextBuffer MAC + Tool $D704 + <<< +~GetRomFont MAC + PHL ]1 +_GetRomFont MAC + Tool $D804 + <<< +~GetFontLore MAC + PHA + PHLW ]1;]2 +_GetFontLore MAC + Tool $D904 + <<< +_Get640Colors MAC + Tool $DA04 + <<< +_Set640Color MAC + Tool $DB04 + <<< +~qQDStartUp MAC + NextDP ]1;$300 + PxW ]2;]3;]4 + Tool $204 + <<< + diff --git a/Library/QdAux.Macs.s b/Library/QdAux.Macs.s new file mode 100644 index 0000000..1f3cf6a --- /dev/null +++ b/Library/QdAux.Macs.s @@ -0,0 +1,86 @@ +* QuickDraw Aux macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_QDAuxBootInit MAC + Tool $112 + <<< +_QDAuxStartUp MAC + Tool $212 + <<< +_QDAuxShutDown MAC + Tool $312 + <<< +~QDAuxVersion MAC + PHA +_QDAuxVersion MAC + Tool $412 + <<< +_QDAuxReset MAC + Tool $512 + <<< +~QDAuxStatus MAC + PHA +_QDAuxStatus MAC + Tool $612 + <<< +~CopyPixels MAC + PxL ]1;]2;]3;]4 + PHWL ]5;]6 +_CopyPixels MAC + Tool $912 + <<< +_WaitCursor MAC + Tool $A12 + <<< +~DrawIcon MAC + PHLW ]1;]2 + PxW ]3;]4 +_DrawIcon MAC + Tool $B12 + <<< +~SpecialRect MAC + PHL ]1 + PxW ]2;]3 +_SpecialRect MAC + Tool $C12 + <<< +~SeedFill MAC + PxL ]1;]2;]3;]4 + PxW ]5;]6;]7 + PxL ]8;]9 +_SeedFill MAC + Tool $D12 + <<< +~CalcMask MAC + PxL ]1;]2;]3;]4 + PHW ]5 + PxL ]6;]7 +_CalcMask MAC + Tool $E12 + <<< +_GetSysIcon MAC + Tool $F12 + <<< +_PixelMap2Rgn MAC + Tool $1012 + <<< +_IBeamCursor MAC + Tool $1312 + <<< +_WhooshRect MAC + Tool $1412 + <<< +_DrawStringWidth MAC + Tool $1512 + <<< +_UseColorTable MAC + Tool $1612 + <<< +_RestoreColorTable MAC + Tool $1712 + <<< + diff --git a/Library/Resource.Macs.s b/Library/Resource.Macs.s new file mode 100644 index 0000000..50b8cc2 --- /dev/null +++ b/Library/Resource.Macs.s @@ -0,0 +1,229 @@ +* Resource macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_ResourceBootInit MAC + Tool $11E + <<< +~ResourceStartUp MAC + PHW ]1 +_ResourceStartUp MAC + Tool $21E + <<< +_ResourceShutDown MAC + Tool $31E + <<< +~ResourceVersion MAC + PHA +_ResourceVersion MAC + Tool $41E + <<< +_ResourceReset MAC + Tool $51E + <<< +~ResourceStatus MAC + PHA +_ResourceStatus MAC + Tool $61E + <<< +~CreateResourceFile MAC + PHLW ]1;]2 + PHWL ]3;]4 +_CreateResourceFile MAC + Tool $91E + <<< +~OpenResourceFile MAC + P1SW ]1 + PxL ]2;]3 +_OpenResourceFile MAC + Tool $A1E + <<< +~CloseResourceFile MAC + PHW ]1 +_CloseResourceFile MAC + Tool $B1E + <<< +~AddResource MAC + PHLW ]1;]2 + PHWL ]3;]4 +_AddResource MAC + Tool $C1E + <<< +~UpdateResourceFile MAC + PHW ]1 +_UpdateResourceFile MAC + Tool $D1E + <<< +~LoadResource MAC + P2SW ]1 + PHL ]2 +_LoadResource MAC + Tool $E1E + <<< +~RemoveResource MAC + PHWL ]1;]2 +_RemoveResource MAC + Tool $F1E + <<< +~MarkResourceChange MAC + PxW ]1;]2 + PHL ]3 +_MarkResourceChange MAC + Tool $101E + <<< +~SetCurResourceFile MAC + PHW ]1 +_SetCurResourceFile MAC + Tool $111E + <<< +~GetCurResourceFile MAC + PHA +_GetCurResourceFile MAC + Tool $121E + <<< +~SetCurResourceApp MAC + PHW ]1 +_SetCurResourceApp MAC + Tool $131E + <<< +~GetCurResourceApp MAC + PHA +_GetCurResourceApp MAC + Tool $141E + <<< +~HomeResourceFile MAC + P1SW ]1 + PHL ]2 +_HomeResourceFile MAC + Tool $151E + <<< +~WriteResource MAC + PHWL ]1;]2 +_WriteResource MAC + Tool $161E + <<< +~ReleaseResource MAC + PxW ]1;]2 + PHL ]3 +_ReleaseResource MAC + Tool $171E + <<< +~DetachResource MAC + PHWL ]1;]2 +_DetachResource MAC + Tool $181E + <<< +~UniqueResourceID MAC + P2SW ]1 + PHW ]2 +_UniqueResourceID MAC + Tool $191E + <<< +~SetResourceID MAC + PHLW ]1;]2 + PHL ]3 +_SetResourceID MAC + Tool $1A1E + <<< +~GetResourceAttr MAC + P1SW ]1 + PHL ]2 +_GetResourceAttr MAC + Tool $1B1E + <<< +~SetResourceAttr MAC + PxW ]1;]2 + PHL ]3 +_SetResourceAttr MAC + Tool $1C1E + <<< +~GetResourceSize MAC + P2SW ]1 + PHL ]2 +_GetResourceSize MAC + Tool $1D1E + <<< +~MatchResourceHandle MAC + PxL ]1;]2 +_MatchResourceHandle MAC + Tool $1E1E + <<< +~GetOpenFileRefNum MAC + P1SW ]1 +_GetOpenFileRefNum MAC + Tool $1F1E + <<< +~CountTypes MAC + PHA +_CountTypes MAC + Tool $201E + <<< +~GetIndType MAC + P1SW ]1 +_GetIndType MAC + Tool $211E + <<< +~CountResources MAC + P2SW ]1 +_CountResources MAC + Tool $221E + <<< +~GetIndResource MAC + P2SW ]1 + PHL ]2 +_GetIndResource MAC + Tool $231E + <<< +~SetResourceLoad MAC + P1SW ]1 +_SetResourceLoad MAC + Tool $241E + <<< +~SetResourceFileDepth MAC + P1SW ]1 +_SetResourceFileDepth MAC + Tool $251E + <<< +~GetMapHandle MAC + P2SW ]1 +_GetMapHandle MAC + Tool $261E + <<< +~LoadAbsResource MAC + P2SL ]1 + PHL ]2 + PHWL ]3;]4 +_LoadAbsResource MAC + Tool $271E + <<< +~ResourceConverter MAC + PHL ]1 + PxW ]2;]3 +_ResourceConverter MAC + Tool $281E + <<< +_LoadResource2 MAC + Tool $291E + <<< +_RMFindeNamedResource MAC + Tool $2A1E + <<< +_RMGetResourceName MAC + Tool $2B1E + <<< +_RMLoadNamedResource MAC + Tool $2C1E + <<< +_RMSetResourceName MAC + Tool $2D1E + <<< +_OpenResourceFileByID MAC + Tool $2E1E + <<< +_CompactResourceFile MAC + Tool $2F1E + <<< + diff --git a/Library/Sane.Macs.s b/Library/Sane.Macs.s new file mode 100644 index 0000000..75a807e --- /dev/null +++ b/Library/Sane.Macs.s @@ -0,0 +1,604 @@ +* Sane Toolset macros. +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_SANEBootInit MAC + Tool $10A + <<< +~SANEStartUp MAC + PHW ]1 +_SANEStartUp MAC + Tool $20A + <<< +_SANEShutDown MAC + Tool $30A + <<< +~SANEVersion MAC + PHA +_SANEVersion MAC + Tool $40A + <<< +_SANEReset MAC + Tool $50A + <<< +~SANEStatus MAC + PHA +_SANEStatus MAC + Tool $60A + <<< +_SANEFP816 MAC + Tool $90A + <<< +_SANEDecStr816 MAC + Tool $A0A + <<< +_SANEElems816 MAC + Tool $B0A + <<< +~qSANEStartUp MAC + NextDP ]1;$100 + Tool $20A + <<< +* Auxiliary macros + +FOPRF MAC ;call FP + PEA ]1 + _SANEFP816 + <<< +FOPRD MAC ;call DecStr + PEA ]1 + _SANEDecStr816 + <<< +FOPRE MAC ;call Elems + PEA ]1 + _SANEElems816 + <<< +* Addition + +FADDX MAC + FOPRF 0 + <<< +FADDD MAC + FOPRF $100 + <<< +FADDS MAC + FOPRF $200 + <<< +FADDC MAC + FOPRF $500 + <<< +FADDI MAC + FOPRF $400 + <<< +FADDL MAC + FOPRF $300 + <<< +* Subtraction + +FSUBX MAC + FOPRF $002 + <<< +FSUBD MAC + FOPRF $102 + <<< +FSUBS MAC + FOPRF $202 + <<< +FSUBC MAC + FOPRF $502 + <<< +FSUBI MAC + FOPRF $402 + <<< +FSUBL MAC + FOPRF $302 + <<< +* Multiplication + +FMULX MAC + FOPRF $004 + <<< +FMULD MAC + FOPRF $104 + <<< +FMULS MAC + FOPRF $204 + <<< +FMULC MAC + FOPRF $504 + <<< +FMULI MAC + FOPRF $404 + <<< +FMULL MAC + FOPRF $304 + <<< +* Division + +FDIVX MAC + FOPRF $006 + <<< +FDIVD MAC + FOPRF $106 + <<< +FDIVS MAC + FOPRF $206 + <<< +FDIVC MAC + FOPRF $506 + <<< +FDIVI MAC + FOPRF $406 + <<< +FDIVL MAC + FOPRF $306 + <<< +* Square root + +FSQRTX MAC + FOPRF $12 + <<< + +* Round to integer, according to the current rounding mode + +FRINTX MAC + FOPRF $14 + <<< + +* Truncate to integer, using round toward zero. + +FTINTX MAC + FOPRF $16 + <<< +* Remainder + +FREMX MAC + FOPRF $00C + <<< +FREMD MAC + FOPRF $10C + <<< +FREMS MAC + FOPRF $20C + <<< +FREMC MAC + FOPRF $50C + <<< +FREMI MAC + FOPRF $40C + <<< +FREML MAC + FOPRF $30C + <<< +* Logb + +FLOGBX MAC + FOPRF $1A + <<< +* Scalb + +FSCALBX MAC + FOPRF $18 + <<< +* Copy-sign + +FCPYSGNX MAC + FOPRF $011 + <<< +FCPYSGND MAC + FOPRF $111 + <<< +FCPYSGNS MAC + FOPRF $211 + <<< +FCPYSGNC MAC + FOPRF $511 + <<< +FCPYSGNI MAC + FOPRF $411 + <<< +FCPYSGNL MAC + FOPRF $311 + <<< +* Negate + +FNEGX MAC + FOPRF $0D + <<< + +* Absolute value + +FABSX MAC + FOPRF $0F + <<< + +* Next-after. NOTE: both operands are of the +* the same format, as specified by the usual suffix. + +FNEXTS MAC + FOPRF $21E + <<< +FNEXTD MAC + FOPRF $11E + <<< +FNEXTX MAC + FOPRF $01E + <<< + +* Conversion to extended + +FX2X MAC + FOPRF $00E + <<< +FD2X MAC + FOPRF $10E + <<< +FS2X MAC + FOPRF $20E + <<< + +* 16-bit integer, by address + +FI2X MAC + FOPRF $40E + <<< + +* 32-bit integer, by address + +FL2X MAC + FOPRF $30E + <<< +FC2X MAC + FOPRF $50E + <<< + +* Conversion from extended + +FX2D MAC + FOPRF $110 + <<< +FX2S MAC + FOPRF $210 + <<< +FX2I MAC + FOPRF $410 + <<< +FX2L MAC + FOPRF $310 + <<< +FX2C MAC + FOPRF $510 + <<< + +* Binary to decimal conversion + +FX2DEC MAC + FOPRF $00B + <<< +FD2DEC MAC + FOPRF $10B + <<< +FS2DEC MAC + FOPRF $20B + <<< +FC2DEC MAC + FOPRF $50B + <<< +FI2DEC MAC + FOPRF $40B + <<< +FL2DEC MAC + FOPRF $30B + <<< + +* Decimal to binary conversion + +FDEC2X MAC + FOPRF $009 + <<< +FDEC2D MAC + FOPRF $109 + <<< +FDEC2S MAC + FOPRF $209 + <<< +FDEC2C MAC + FOPRF $509 + <<< +FDEC2I MAC + FOPRF $409 + <<< +FDEC2L MAC + FOPRF $309 + <<< + +* Compare, not signaling invalid on unordered + +FCMPX MAC + FOPRF $008 + <<< +FCMPD MAC + FOPRF $108 + <<< +FCMPS MAC + FOPRF $208 + <<< +FCMPC MAC + FOPRF $508 + <<< +FCMPI MAC + FOPRF $408 + <<< +FCMPL MAC + FOPRF $308 + <<< + +* Compare, signaling invalid on unordered + +FCPXX MAC + FOPRF $00A + <<< +FCPXD MAC + FOPRF $10A + <<< +FCPXS MAC + FOPRF $20A + <<< +FCPXC MAC + FOPRF $50A + <<< +FCPXI MAC + FOPRF $40A + <<< +FCPXL MAC + FOPRF $30A + <<< + +* The following macros define a set of so-called floating +* branches. They presume that the appropriate compare +* operation, macro FCMPz or FCPXz, precedes. + +FBEQ MAC + BEQ ]1 + <<< +FBLT MAC ;less + BMI ]1 + <<< +FBLE MAC ;less or equal + BMI ]1 + BEQ ]1 + <<< +FBGT MAC ;greater + BVS ]1 + <<< +FBGE MAC ;greater or equal + BVS ]1 + BEQ ]1 + <<< +FBULT MAC ;less or unordered + BMI ]1 + BVS *+4 + BNE ]1 + <<< +FBULE MAC ;unordered, less, or equal + BMI ]1 + BEQ ]1 + BVC ]1 + <<< +FBUGT MAC ;unordered or greater + BVS ]1 + BMI *+4 + BNE ]1 + <<< +FBUGE MAC ;unordered, greater, or equal + BVS ]1 + BEQ ]1 + BPL ]1 + <<< +FBU MAC ;unordered + BVS *+6 + BMI *+4 + BNE ]1 + <<< +FBO MAC ;ordered + BMI ]1 + BVS ]1 + BEQ ]1 + <<< +FBNE MAC ;not equal + BMI ]1 + BVS ]1 + BNE ]1 + <<< +FBUE MAC ;unordered, equal + BEQ ]1 + BMI *+4 + BVC ]1 + <<< +FBLG MAC ;less or greater + BMI ]1 + BVS ]1 + <<< + +FCLASSS MAC + FOPRF $21C + <<< +FCLASSD MAC + FOPRF $11C + <<< +FCLASSX MAC + FOPRF $01C + <<< +FCLASSC MAC + FOPRF $51C + <<< +FCLASSI MAC + FOPRF $41C + <<< +FCLASSL MAC + FOPRF $31C + <<< + +* The following macros provide branches based on the +* the result of a FCLASSz macro. + +FBSNAN MAC ;signaling NaN + TXA + ASL + CMP #2*$FC + BEQ ]1 + <<< +FBQNAN MAC ;quiet NaN + TXA + ASL + CMP #2*$FD + BEQ ]1 + <<< +FBINF MAC ;infinite + TXA + ASL + CMP #2*$FE + BEQ ]1 + <<< +FBZERO MAC ;zero + TXA + ASL + CMP #2*$FF + BEQ ]1 + <<< +FBNORM MAC ;normal + TXA + ASL + BEQ ]1 + <<< +FBDENORM MAC ;denormal + TXA + ASL + CMP #2*1 + BEQ ]1 + <<< +FBNZENUM MAC ;non-zero num (norm or denorm) + TXA + XBA + ASL + BCC ]1 + <<< +FBNUM MAC ;number (zero, norm or denorm) + TXA + INC A + XBA + ASL + BCC ]1 + <<< +FBMINUS MAC ;minus sign + BMI ]1 + <<< +FBPLUS MAC ;plus sign + BPL ]1 + <<< + +* Get and set environment + +FGETENV MAC + FOPRF $03 + <<< +FSETENV MAC + FOPRF $01 + <<< + +* Test and set exception + +FTESTXCP MAC + FOPRF $1B + <<< +FSETXCP MAC + FOPRF $15 + <<< + +* Procedure entry and exit + +FPROCENTRY MAC + FOPRF $17 + <<< +FPROCEXIT MAC + FOPRF $19 + <<< + +* Get and set halt vector + +FGETHV MAC + FOPRF $07 + <<< +FSETHV MAC + FOPRF $05 + <<< + +* Elementary function macros + +FLNX MAC ;natural (base-e) log + FOPRE $00 + <<< +FLOG2X MAC ;base-2 log + FOPRE $02 + <<< +FLN1X MAC ;ln (1 + x) + FOPRE $04 + <<< +FLOG21X MAC ;log2 (1 +x) + FOPRE $06 + <<< +FEXPX MAC ;base-e exponential + FOPRE $08 + <<< +FEXP2X MAC ;base-2 exponential + FOPRE $0A + <<< +FEXP1X MAC ;exp (x) - 1 + FOPRE $0C + <<< +FEXP21X MAC ;exp2 (x) - 1 + FOPRE $0E + <<< +FXPWRI MAC ;integer exponential + FOPRE $10 + <<< +FXPWRY MAC ;general exponential + FOPRE $12 + <<< +FCOMPOUND MAC ;compound + FOPRE $14 + <<< +FANNUITY MAC ;annuity + FOPRE $16 + <<< +FATANX MAC ;arctangent + FOPRE $18 + <<< +FSINX MAC ;sine + FOPRE $1A + <<< +FCOSX MAC ;cosine + FOPRE $1C + <<< +FTANX MAC ;tangent + FOPRE $1E + <<< +FRANDX MAC ;random number generator + FOPRE $20 + <<< + +* Scanner and formatter function macros + +FPSTR2DEC MAC ;pascal string to decimal record + FOPRD 0 + <<< +FDEC2STR MAC ;decimal record to pascal string + FOPRD 1 + <<< +FCSTR2DEC MAC ;C string to decimal record + FOPRD 2 + <<< + diff --git a/Library/Sch.Macs.s b/Library/Sch.Macs.s new file mode 100644 index 0000000..c0cbbd7 --- /dev/null +++ b/Library/Sch.Macs.s @@ -0,0 +1,38 @@ +* Scheduler macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_SchBootInit MAC + Tool $107 + <<< +_SchStartUp MAC + Tool $207 + <<< +_SchShutDown MAC + Tool $307 + <<< +~SchVersion MAC + PHA +_SchVersion MAC + Tool $407 + <<< +_SchReset MAC + Tool $507 + <<< +~SchStatus MAC + PHA +_SchStatus MAC + Tool $607 + <<< +~SchAddTask MAC + P1SL ]1 +_SchAddTask MAC + Tool $907 + <<< +_SchFlush MAC + Tool $A07 + <<< + diff --git a/Library/Scrap.Macs.s b/Library/Scrap.Macs.s new file mode 100644 index 0000000..180166a --- /dev/null +++ b/Library/Scrap.Macs.s @@ -0,0 +1,86 @@ +* Scrap manager macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_ScrapBootInit MAC + Tool $116 + <<< +_ScrapStartUp MAC + Tool $216 + <<< +_ScrapShutDown MAC + Tool $316 + <<< +~ScrapVersion MAC + PHA +_ScrapVersion MAC + Tool $416 + <<< +_ScrapReset MAC + Tool $516 + <<< +~ScrapStatus MAC + PHA +_ScrapStatus MAC + Tool $616 + <<< +_UnloadScrap MAC + Tool $916 + <<< +_LoadScrap MAC + Tool $A16 + <<< +_ZeroScrap MAC + Tool $B16 + <<< +~PutScrap MAC + PHL ]1 + PHWL ]2;]3 +_PutScrap MAC + Tool $C16 + <<< +~GetScrap MAC + PHLW ]1;]2 +_GetScrap MAC + Tool $D16 + <<< +~GetScrapHandle MAC + P2SW ]1 +_GetScrapHandle MAC + Tool $E16 + <<< +~GetScrapSize MAC + P2SW ]1 +_GetScrapSize MAC + Tool $F16 + <<< +~GetScrapPath MAC + PHS 2 +_GetScrapPath MAC + Tool $1016 + <<< +~SetScrapPath MAC + PHL ]1 +_SetScrapPath MAC + Tool $1116 + <<< +~GetScrapCount MAC + PHA +_GetScrapCount MAC + Tool $1216 + <<< +~GetScrapState MAC + PHA +_GetScrapState MAC + Tool $1316 + <<< +_GetIndScrap MAC + Tool $1416 + <<< +_ShowClipboard MAC + Tool $1516 + <<< + diff --git a/Library/Sound.Macs.s b/Library/Sound.Macs.s new file mode 100644 index 0000000..13f1323 --- /dev/null +++ b/Library/Sound.Macs.s @@ -0,0 +1,111 @@ +* Sound manager macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_SoundBootInit MAC + Tool $108 + <<< +~SoundStartUp MAC + PHW ]1 +_SoundStartUp MAC + Tool $208 + <<< +_SoundShutDown MAC + Tool $308 + <<< +~SoundVersion MAC + PHA +_SoundVersion MAC + Tool $408 + <<< +_SoundReset MAC + Tool $508 + <<< +~SoundToolStatus MAC + PHA +_SoundToolStatus MAC + Tool $608 + <<< +~WriteRamBlock MAC + PHL ]1 + PxW ]2;]3 +_WriteRamBlock MAC + Tool $908 + <<< +~ReadRamBlock MAC + PHL ]1 + PxW ]2;]3 +_ReadRamBlock MAC + Tool $A08 + <<< +~GetTableAddress MAC + PHS 2 +_GetTableAddress MAC + Tool $B08 + <<< +~GetSoundVolume MAC + P1SW ]1 +_GetSoundVolume MAC + Tool $C08 + <<< +~SetSoundVolume MAC + PxW ]1;]2 +_SetSoundVolume MAC + Tool $D08 + <<< +~FFStartSound MAC + PHWL ]1;]2 +_FFStartSound MAC + Tool $E08 + <<< +~FFStopSound MAC + PHW ]1 +_FFStopSound MAC + Tool $F08 + <<< +~FFSoundStatus MAC + PHA +_FFSoundStatus MAC + Tool $1008 + <<< +~FFGeneratorStatus MAC + P1SW ]1 +_FFGeneratorStatus MAC + Tool $1108 + <<< +~SetSoundMIRQV MAC + PHL ]1 +_SetSoundMIRQV MAC + Tool $1208 + <<< +~SetUserSoundIRQV MAC + P2SL ]1 +_SetUserSoundIRQV MAC + Tool $1308 + <<< +~FFSoundDoneStatus MAC + P1SW ]1 +_FFSoundDoneStatus MAC + Tool $1408 + <<< +_FFSetUpSound MAC + Tool $1508 + <<< +_FFStartPlaying MAC + Tool $1608 + <<< +_SetDocReg MAC + Tool $1708 + <<< +_ReadDocReg MAC + Tool $1808 + <<< + +~qSoundStartUp MAC + NextDP ]1;$100 + Tool $208 + <<< + diff --git a/Library/Speech.Macs.s b/Library/Speech.Macs.s new file mode 100644 index 0000000..8ac5741 --- /dev/null +++ b/Library/Speech.Macs.s @@ -0,0 +1,47 @@ +* +* Speech Toolkit tool calls +* + +_SpeechBootInit mac + Tool $0134 + <<< +_SpeechStartUp mac + Tool $0234 + <<< +_SpeechShutDown mac + Tool $0334 + <<< +_SpeechVersion mac + Tool $0434 + <<< +_SpeechReset mac + Tool $0534 + <<< +_SpeechStatus mac + Tool $0634 + <<< +_Parse mac + Tool $0934 + <<< +_DictInsert mac + Tool $0a34 + <<< +_DictDelete mac + Tool $0b34 + <<< +_DictDump mac + Tool $0c34 + <<< +_SetSayGlobals mac + Tool $0d34 + <<< +_DictInit mac + Tool $0e34 + <<< +_Say mac + Tool $0f34 + <<< +_Activate mac + Tool $1034 + <<< + diff --git a/Library/Std.Macs.s b/Library/Std.Macs.s new file mode 100644 index 0000000..f5f22fd --- /dev/null +++ b/Library/Std.Macs.s @@ -0,0 +1,108 @@ +* Standard File Operations macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_SFBootInit MAC + Tool $117 + <<< +~SFStartUp MAC + PxW ]1;]2 +_SFStartUp MAC + Tool $217 + <<< +_SFShutDown MAC + Tool $317 + <<< +~SFVersion MAC + PHA +_SFVersion MAC + Tool $417 + <<< +_SFReset MAC + Tool $517 + <<< +~SFStatus MAC + PHA +_SFStatus MAC + Tool $617 + <<< +~SFGetFile MAC + PxW ]1;]2 + PxL ]3;]4;]5;]6 +_SFGetFile MAC + Tool $917 + <<< +~SFPutFile MAC + PxW ]1;]2 + PxL ]3;]4 + PHWL ]5;]6 +_SFPutFile MAC + Tool $A17 + <<< +~SFPGetFile MAC + PxW ]1;]2 + PxL ]3;]4;]5;]6 + PxL ]7;]8 +_SFPGetFile MAC + Tool $B17 + <<< +~SFPPutFile MAC + PxW ]1;]2 + PxL ]3;]4 + PHWL ]5;]6 + PxL ]7;]8 +_SFPPutFile MAC + Tool $C17 + <<< +~SFAllCaps MAC + PHW ]1 +_SFAllCaps MAC + Tool $D17 + <<< +~SFGetFile2 MAC + PxW ]1;]2;]3 + PxL ]4;]5;]6;]7 +_SFGetFile2 MAC + Tool $E17 + <<< +~SFPutFile2 MAC + PxW ]1;]2;]3 + PHLW ]4;]5 + PxL ]6;]7 +_SFPutFile2 MAC + Tool $F17 + <<< +_SFPGetFile2 MAC + Tool $1017 + <<< +_SFPPutFile2 MAC + Tool $1117 + <<< +~SFShowInvisible MAC + P1SW ]1 +_SFShowInvisible MAC + Tool $1217 + <<< +~SFReScan MAC + PxL ]1;]2 +_SFReScan MAC + Tool $1317 + <<< +~SFMultiGet2 MAC + PxW ]1;]2;]3 + PxL ]4;]5;]6;]7 +_SFMultiGet2 MAC + Tool $1417 + <<< +_SFPMultiGet2 MAC + Tool $1517 + <<< +~qSFStartUp MAC + PHW ]1 + NextDP ]2;$100 + Tool $217 + <<< + diff --git a/Library/Text.Macs.s b/Library/Text.Macs.s new file mode 100644 index 0000000..29e2f00 --- /dev/null +++ b/Library/Text.Macs.s @@ -0,0 +1,184 @@ +* Text tool macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_TextBootInit MAC + Tool $10C + <<< +_TextStartUp MAC + Tool $20C + <<< +_TextShutDown MAC + Tool $30C + <<< +~TextVersion MAC + PHA +_TextVersion MAC + Tool $40C + <<< +_TextReset MAC + Tool $50C + <<< +~TextStatus MAC + PHA +_TextStatus MAC + Tool $60C + <<< +~SetInGlobals MAC + PxW ]1;]2 +_SetInGlobals MAC + Tool $90C + <<< +~SetOutGlobals MAC + PxW ]1;]2 +_SetOutGlobals MAC + Tool $A0C + <<< +~SetErrGlobals MAC + PxW ]1;]2 +_SetErrGlobals MAC + Tool $B0C + <<< +~GetInGlobals MAC + PHS 2 +_GetInGlobals MAC + Tool $C0C + <<< +~GetOutGlobals MAC + PHS 2 +_GetOutGlobals MAC + Tool $D0C + <<< +~GetErrGlobals MAC + PHS 2 +_GetErrGlobals MAC + Tool $E0C + <<< +~SetInputDevice MAC + PHWL ]1;]2 +_SetInputDevice MAC + Tool $F0C + <<< +~SetOutputDevice MAC + PHWL ]1;]2 +_SetOutputDevice MAC + Tool $100C + <<< +~SetErrorDevice MAC + PHWL ]1;]2 +_SetErrorDevice MAC + Tool $110C + <<< +~GetInputDevice MAC + PHS 3 +_GetInputDevice MAC + Tool $120C + <<< +~GetOutputDevice MAC + PHS 3 +_GetOutputDevice MAC + Tool $130C + <<< +~GetErrorDevice MAC + PHS 3 +_GetErrorDevice MAC + Tool $140C + <<< +~InitTextDev MAC + PHW ]1 +_InitTextDev MAC + Tool $150C + <<< +~CtlTextDev MAC + PxW ]1;]2 +_CtlTextDev MAC + Tool $160C + <<< +~StatusTextDev MAC + PxW ]1;]2 +_StatusTextDev MAC + Tool $170C + <<< +~WriteChar MAC + PHW ]1 +_WriteChar MAC + Tool $180C + <<< +~ErrWriteChar MAC + PHW ]1 +_ErrWriteChar MAC + Tool $190C + <<< +~WriteLine MAC + PHL ]1 +_WriteLine MAC + Tool $1A0C + <<< +~ErrWriteLine MAC + PHL ]1 +_ErrWriteLine MAC + Tool $1B0C + <<< +~WriteString MAC + PHL ]1 +_WriteString MAC + Tool $1C0C + <<< +~ErrWriteString MAC + PHL ]1 +_ErrWriteString MAC + Tool $1D0C + <<< +~TextWriteBlock MAC + PHL ]1 + PxW ]2;]3 +_TextWriteBlock MAC + Tool $1E0C + <<< +~ErrWriteBlock MAC + PHL ]1 + PxW ]2;]3 +_ErrWriteBlock MAC + Tool $1F0C + <<< +~WriteCString MAC + PHL ]1 +_WriteCString MAC + Tool $200C + <<< +~ErrWriteCString MAC + PHL ]1 +_ErrWriteCString MAC + Tool $210C + <<< +~ReadChar MAC + P1SW ]1 +_ReadChar MAC + Tool $220C + <<< +~TextReadBlock MAC + PHL ]1 + PxW ]2;]3;]4 +_TextReadBlock MAC + Tool $230C + <<< +~ReadLine MAC + P1SL ]1 + PxW ]2;]3;]4 +_ReadLine MAC + Tool $240C + <<< + +PrintLn MAC ; print a line of text + pea ^text + pea text + ldx #$1A0C + jsl $E10000 + bra cont +text str ]1 +cont + <<< + diff --git a/Library/TextEdit.Macs.s b/Library/TextEdit.Macs.s new file mode 100644 index 0000000..f5d369b --- /dev/null +++ b/Library/TextEdit.Macs.s @@ -0,0 +1,199 @@ +* TextEdit macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_TEBootInit MAC + Tool $122 + <<< +~TEStartUp MAC + PxW ]1;]2 +_TEStartUp MAC + Tool $222 + <<< +_TEShutDown MAC + Tool $322 + <<< +~TEVersion MAC + PHA +_TEVersion MAC + Tool $422 + <<< +_TEReset MAC + Tool $522 + <<< +~TEStatus MAC + PHA +_TEStatus MAC + Tool $622 + <<< +~TENew MAC + P2SL ]1 +_TENew MAC + Tool $922 + <<< +~TEKill MAC + PHL ]1 +_TEKill MAC + Tool $A22 + <<< +~TESetText MAC + PHWL ]1;]2 + PHLW ]3;]4 + PxL ]5;]6 +_TESetText MAC + Tool $B22 + <<< +~TEGetText MAC + PHS 2 + PHWL ]1;]2 + PHLW ]3;]4 + PxL ]5;]6 +_TEGetText MAC + Tool $C22 + <<< +~TEGetTextInfo MAC + PHLW ]1;]2 + PHL ]3 +_TEGetTextInfo MAC + Tool $D22 + <<< +~TEIdle MAC + PHL ]1 +_TEIdle MAC + Tool $E22 + <<< +~TEActivate MAC + PHL ]1 +_TEActivate MAC + Tool $F22 + <<< +~TEDeactivate MAC + PHL ]1 +_TEDeactivate MAC + Tool $1022 + <<< +~TEClick MAC + PxL ]1;]2 +_TEClick MAC + Tool $1122 + <<< +~TEUpdate MAC + PHL ]1 +_TEUpdate MAC + Tool $1222 + <<< +~TEPaintText MAC + P2SL ]1 + PxL ]2;]3 + PHWL ]4;]5 +_TEPaintText MAC + Tool $1322 + <<< +~TEKey MAC + PxL ]1;]2 +_TEKey MAC + Tool $1422 + <<< +~TECut MAC + PHL ]1 +_TECut MAC + Tool $1622 + <<< +~TECopy MAC + PHL ]1 +_TECopy MAC + Tool $1722 + <<< +~TEPaste MAC + PHL ]1 +_TEPaste MAC + Tool $1822 + <<< +~TEClear MAC + PHL ]1 +_TEClear MAC + Tool $1922 + <<< +~TEInsert MAC + PHWL ]1;]2 + PHLW ]3;]4 + PxL ]5;]6 +_TEInsert MAC + Tool $1A22 + <<< +~TEReplace MAC + PHWL ]1;]2 + PHLW ]3;]4 + PxL ]5;]6 +_TEReplace MAC + Tool $1B22 + <<< +~TEGetSelection MAC + PxL ]1;]2;]3 +_TEGetSelection MAC + Tool $1C22 + <<< +~TESetSelection MAC + PxL ]1;]2;]3 +_TESetSelection MAC + Tool $1D22 + <<< +~TEGetSelectionStyle MAC + PHA + PxL ]1;]2;]3 +_TEGetSelectionStyle MAC + Tool $1E22 + <<< +~TEStyleChange MAC + PHW ]1 + PxL ]2;]3 +_TEStyleChange MAC + Tool $1F22 + <<< +~TEOffsetToPoint MAC + PxL ]1;]2;]3;]4 +_TEOffsetToPoint MAC + Tool $2022 + <<< +~TEPointToOffset MAC + PHS 2 + PxL ]1;]2;]3 +_TEPointToOffset MAC + Tool $2122 + <<< +~TEGetDefProc MAC + PHS 2 +_TEGetDefProc MAC + Tool $2222 + <<< +~TEGetRuler MAC + PHWL ]1;]2 + PHL ]3 +_TEGetRuler MAC + Tool $2322 + <<< +~TESetRuler MAC + PHW ]1 + PxL ]2;]3 +_TESetRuler MAC + Tool $2422 + <<< +~TEScroll MAC + PHW ]1 + PxL ]2;]3;]4 +_TEScroll MAC + Tool $2522 + <<< +_TEGetInternalProc MAC + Tool $2622 + <<< +_TEGetLastError MAC + Tool $2722 + <<< +_TECompactRecord MAC + Tool $2822 + <<< + diff --git a/Library/Tool219.Macs.s b/Library/Tool219.Macs.s new file mode 100644 index 0000000..ceb4af4 --- /dev/null +++ b/Library/Tool219.Macs.s @@ -0,0 +1,86 @@ +* SoundSmith Tool +* FTA, 1991 + +~STStartUp mac + PHW ]1 +_STStartUp mac + Tool $02DB + <<< +_STShutDown mac + Tool $03DB + <<< +~STVersion mac + phd ; WordResult +_STVersion mac + Tool $04DB + <<< +_STReset mac + Tool $05DB + <<< +~STStatus mac + phd ; WordResult +STStatus mac + Tool $06DB + <<< +~STLoadOneMusic mac + PHL ]1 +_STLoadOneMusic mac + Tool $09DB + <<< +~STPlayMusic mac + PHW ]1 +_STPlayMusic mac + Tool $0ADB + <<< +_STStopMusic mac + Tool $0BDB + <<< +~STGetEOfMusic mac + phd ; WordResult +_STGetEOfMusic mac + Tool $0CDB + <<< +~STAddToBatch mac + PHLW ]1;]2 +_STAddToBatch mac + Toll $0DDB + <<< +~STSelectBatch mac + PHW ]1 +_STSelectBatch mac + Tool $0EDB + <<< +~STKillBatch mac + PHW ]1 +_STKillBatch mac + Tool $0FDB + <<< +~STGetPlayingMusic mac + phd ; WordResult +_STGetPlayingMusic mac + Tool $10DB + <<< +~STPlayBatch mac + PHL ]1 +_STPlayBatch mac + Tool $11DB + <<< +~STGetTrackVu mac + phd ;Long + phd ; Result +_STGetTrackVu mac + Tool $12DB + <<< +_STPauseMusic mac + Tool $13DB + <<< +_STContinueMusic mac + Tool $14DB + <<< +_STinternal15 mac + Tool $15DB + <<< +_STinternal16 mac + Tool $16DB + <<< + diff --git a/Library/Tool220.Macs.s b/Library/Tool220.Macs.s new file mode 100644 index 0000000..b1b59dd --- /dev/null +++ b/Library/Tool220.Macs.s @@ -0,0 +1,34 @@ +* NoiseTracker Tool +* FTA, 1992 + +_NTBootInit mac + Tool $01dc + <<< +_NTStartUp mac + Tool $02dc + <<< +_NTShutDown mac + Tool $03dc + <<< +_NTVersion mac + Tool $04dc + <<< +_NTReset mac + Tool $05dc + <<< +_NTStatus mac + Tool $06dc + <<< +_NTInitMusic mac + Tool $09dc + <<< +_NTLaunchMusic mac + Tool $0adc + <<< +_NTUpdateSound mac + Tool $0bdc + <<< +_NTStopMusic mac + Tool $0cdc + <<< + diff --git a/Library/Util.Macs.s b/Library/Util.Macs.s new file mode 100644 index 0000000..8512647 --- /dev/null +++ b/Library/Util.Macs.s @@ -0,0 +1,796 @@ +*================================================= +* Utility Macros - from Merlin disk +* by Dave Klimas, et al +* +* Copyright Apple Computer, Inc. 1986, 1987 +* and Roger Wagner Publishing, Inc. 1988 +* All Rights Reserved +*------------------------------------------------- + +PHWL MAC + PHW ]1 + PHL ]2 + <<< +PHLW MAC + PHL ]1 + PHW ]2 + <<< +PxW MAC + DO ]0/1 + PHW ]1 + DO ]0/2 + PHW ]2 + DO ]0/3 + PHW ]3 + DO ]0/4 + PHW ]4 + FIN + FIN + FIN + FIN + <<< +PxL MAC + DO ]0/1 + PHL ]1 + DO ]0/2 + PHL ]2 + DO ]0/3 + PHL ]3 + DO ]0/4 + PHL ]4 + FIN + FIN + FIN + FIN + <<< +P2SL MAC + PHA +P1SL MAC + PHA +PHL MAC + IF #=]1 + PEA ^]1 + ELSE + PHW ]1+2 + FIN + PHW ]1 + <<< +P2SW MAC + PHA +P1SW MAC + PHA +PHW MAC + IF #=]1 + PEA ]1 + ELSE + IF MX/2 + LDA ]1+1 + PHA + FIN + LDA ]1 + PHA + FIN + <<< +PushSpace MAC +PHS MAC + DO ]0 + LUP ]1 + PHA + --^ + ELSE + PHA + FIN + <<< + +******************************** + +Push4 MAC + PushLong #0 + PushLong #0 + <<< + +PushPtr MAC + PEA ^]1 + PEA ]1 + EOM + +PushLong MAC + IF #=]1 + PushWord #^]1 + ELSE + PushWord ]1+2 + FIN + PushWord ]1 + <<< + +PushWord MAC + IF #=]1 + PEA ]1 + ELSE + IF MX/2 + LDA ]1+1 + PHA + FIN + LDA ]1 + PHA + FIN + <<< + +PullLong MAC + DO ]0 + PullWord ]1 + PullWord ]1+2 + ELSE + PullWord + PullWord + FIN + <<< + +PullWord MAC + PLA + DO ]0 + STA ]1 + FIN + IF MX/2 + PLA + DO ]0 + STA ]1+1 + FIN + FIN + <<< + +MoveLong MAC + MoveWord ]1;]2 + MoveWord ]1+2;]2+2 + <<< + +MoveWord MAC + LDA ]1 + STA ]2 + IF MX/2 + LDA ]1+1 + STA ]2+1 + FIN + <<< + +MoveBlock MAC ;1st_byte;last_byte;dest + DO ]2/]1 + DO ]3/]1 + LDX #]2 + LDY #]3+]2-]1 + LDA #]2-]1 + MVP ]1,]3 + ELSE + LDX #]1 + LDY #]3 + LDA #]2-]1 + MVN ]1,]3 + FIN + ELSE + ERR 1 ;Last adrs < first adrs + FIN + <<< + +CmpLong MAC + LDA ]1 + CMP ]2 + IF #=]1 + LDA ^]1 + ELSE + LDA ]1+2 + FIN + IF #=]2 + SBC ^]2 + ELSE + SBC ]2+2 + FIN + <<< + +LONGM MAC +LONGACC MAC ;Assumes native mode + IF MX&2 ;If A is now short + REP %00100000 + FIN + <<< + +LONGX MAC +LONGXY MAC ;Assumes native mode + IF MX&1 ;If X is now short + REP %00010000 + FIN + <<< + +LONG MAC +LONGAX MAC ;Assumes native mode + IF MX ;If not now in full 16 + REP %00110000 + FIN + <<< + +SHORTM MAC +SHORTACC MAC ;Assumes native mode + IF MX&2 ;If A is now short, + ELSE ; ignore + SEP %00100000 + FIN + <<< + +SHORTX MAC +SHORTXY MAC ;Assumes native mode + IF MX&1 ;If X is now short, + ELSE ; ignore + SEP %00010000 + FIN + <<< + +SHORT MAC +SHORTAX MAC ;Assumes native mode + IF MX!%11 ;If not now in full 8 + SEP %00110000 + FIN + <<< + +LONGI MAC ; Duplicates APW function + LST OFF + DO ]1 ; If arg = 1 = "on" = make long + + IF MX-3/-1 ; If M is short and X is long +; Leave alone + FIN ; End of this test + + IF MX/3 ; If M is short and X is short + MX %10 ; Make X long, leave M short + FIN ; End of this test + + IF MX!3/3 ; If M is long and X is long + FIN ; Leave alone + + IF MX-2/-1 ; If M is long and X is short + MX %00 ; Make X long, leave M long + FIN ; End of this test + + ELSE ; If arg = 0 = "off" = make short + + IF MX/3 ; If M is short and X is short + ; Leave alone + FIN ; End of this test + + IF MX-3/-1 ; If M is short and X is long + MX %11 ; Make X short, leave M short + FIN ; End of this test + + IF MX-2/-1 ; If M is long and X is short + ; Leave alone + FIN ; End of this test + + + IF MX!3/3 ; If M is long and X is long + MX %01 ; Make X short, leave M long + FIN ; Leave alone + + FIN ; End of macro tests + + LST RTN + <<< + +LONGA MAC ; Duplicates APW function + LST OFF + DO ]1 ; If arg = 1 = "on" = make long + + IF MX-3/-1 ; If M is short and X is long + MX %00 ; Make M long, leave X long + FIN ; End of this test + + IF MX/3 ; If M is short and X is short + MX %01 ; Make M long, leave X short + FIN ; End of this test + + IF MX!3/3 ; If M is long and X is long + FIN ; Leave alone + + IF MX-2/-1 ; If M is long and X is short + ; Leave alone + FIN ; End of this test + + ELSE ; If arg = 0 = "off" = make short + + IF MX/3 ; If M is short and X is short + ; Leave alone + FIN ; End of this test + + IF MX-3/-1 ; If M is short and X is long + ; Leave alone + FIN ; End of this test + + IF MX-2/-1 ; If M is long and X is short + MX %11 ; Make M short, leave X short + FIN ; End of this test + + + IF MX!3/3 ; If M is long and X is long + MX %10 ; Make M short, leave X long + FIN ; Leave alone + + FIN ; End of macro tests + + LST RTN + <<< + +M65816 MAC + DO ]1 + XC + XC ; Full 65816 mode for assembler + MX %00 + ELSE + MX %11 ; 8 bit mode for assembler + FIN + <<< + +Expmac MAC ; Replace APW GEN function + DO ]1 + EXP ONLY ; Expand macros + ELSE + EXP OFF + FIN + <<< + +Tool MAC + LDX #]1 ; load tool call # + JSL $E10000 ; go to dispatcher + <<< + +************************************************** +* Auto-menu item macros * +* This is one alternative for defining a menu * +* item. It has the advantage of letting you * +* include specifiers for Bold, Italic, etc. * +************************************************** + +*------------------------------------------------- +* Syntax: +* ]mnum = 0 ; initialize menu # at startvalue-1 +* Menu ' Menu 1 ' +* +* (See Menu macro, defined later....) +* +* ]inum = 255 ; Menu item starts with #256 +* Item ' Choice 1 ';Kybd;'Bb';Check +* Ch1 = ]inum ; Set label Ch1 if somewhere else +* needs to use this item #. +* Item ' Choice 2 ';Disable;'';Kybd;'Cc' +* Item ' Choice 3 ';Divide;'' +* +* Menu ' Menu 2 ' +* +* Item ' Choice 4 ';Bold;'';Check +* Item ' Choice 5 ';Italic;'';Blank +* Item ' Choice 6 ';Underline';Kybd;'Dd' +* +* IMPORTANT: ALL items, except for Check and Blank, are followed by a second +* value. For the Kybd item, the ASCII characters follow in single quotes, Ex: +* Kybd;'Cc' (specifies Apple-C as an equivalent). +* All other items use a null 2nd value, as in: +* Italic;'' or Divide;'' etc. +* +* The variable ]inum MUST be initialized for the value of your first +* menu item MINUS 1 before using the first Item macro. +* +* Check or Blank, if used, MUST be the last item in the macro line. +* +* There can be up to three parameter pairs after the item name. +*------------------------------------------------- +* The point of all this is that rather than hard- +* code menu items values and subsequent references +* to that number when disabling menus, etc., this +* lets you add and delete menu items at will, +* and have labels like Ch1, etc. above, auto- +* matically set for the correct value during the +* assembly. +*------------------------------------------------- + +* Equates for Item macro: + +Bold = 'B' ; bold menu item +Disable = 'D' ; disabled menu item +Italic = 'I' ; italic menu item +Underline = 'U' ; underlined menu item +Divide = 'V' ; menu dividing line +ColorHi = 'X' ; color hilite menu item +Kybd = '*' ; keyboard menu equivalent +Check = $1243 ; menu item with checkmark +Blank = $2043 ; menu item with blank + +*------------------------------------------------- + +Item MAC ; Macro for creating a menu item + + ASC '--' + ASC ]1 ; Text of menu item + ASC '\H' + DA ]inum ; Menu item # + + DO ]0/2 ; Only if more items to do... (>2) + + DO ]2-Check-1/-1 ; Only if Check item + DA ]2 ; ]2 = Check + ELSE ; otherwise kybd char or null + DO ]2-Blank-1/-1 ; Only if Blank check item + DA ]2 ; ]2 = Blank + ELSE + DB ]2 ; Function char value + ASC ]3 ; ASCII argument, if any for Kybd + FIN + FIN + + FIN + + DO ]0/4 ; Only if more items to do... (>3) + + DO ]4-Check-1/-1 ; Only if Check item + DA ]4 ; ]4 = Check + ELSE ; otherwise kybd char or null + DO ]4-Blank-1/-1 ; Only if Blank check item + DA ]4 ; ]4 = Blank + ELSE + DB ]4 ; Function char value + ASC ]5 ; ASCII argument, if any for Kybd + FIN + FIN + + FIN + + DO ]0/6 ; Only if more items to do... (>5) + + DO ]6-Check-1/-1 ; Only if Check item + DA ]6 ; ]6 = Check + ELSE ; otherwise kybd char or null + DO ]6-Blank-1/-1 ; Only if Blank check item + DA ]6 ; ]6 = Blank + ELSE + DB ]6 ; Function char value + ASC ]7 ; ASCII argument, if any for Kybd + FIN + FIN + + FIN + + DB $00 ; End of menu item + +]inum = ]inum+1 + <<< + +************************************************** +* This is another alternative macro for both * +* menus and menu items. It is simpler, and * +* more compact, but not as versatile. * +************************************************** + +*=============================================== +* Variables ]mnum,]inum should be defined +* prior to using these MenuMaker macros. +* +* They both should be starting value-1 +* +* Syntax: +* +* ]mnum = 0 ; 1st menu number will be 1 +* ]inum = 255 ; 1st menu item number will be 256 +* +* Menu ' @';X ; Apple menu, color highlighting. +* +* MItem ' About... ' ; "About" menu item +* +* Menu ' Menu Title 1' ; (this will be menu number 2) +* +* MItem ' Choice 1 ' +* MItem ' Choice 2 ';'D*Cc' ; Disabled, kybd char: Cc +* ; Above will be menu item #'s 2&3 +* +* + + +Menu MAC + ASC '>>' + ASC ]1 + ASC '\H' + DA ]mnum + DO ]0>1 + ASC ]2 + FIN + DB 0 +]mnum = ]mnum+1 + <<< + +MItem MAC + ASC '--' + ASC ]1 + ASC '\H' + DA ]inum + DO ]0>1 + ASC ]2 + FIN + DB 0 +]inum = ]inum+1 + <<< + +*----------------------------------------------------- +* +* Native -- Processor is in LONG "native" mode. +* Native Long -- Processor is in LONG "native" mode. +* Native Short -- Processor is in SHORT "native" mode. +* + +Native MAC + CLC + XCE + IF 0=]0 ;If Native (Long) + LONGAX + FIN + + DO ]0 + IF L=]1 ;If Native Long + LONGAX + + FIN ;If Native Short only + FIN ; do CLC, XCE. + EOM + +*-------------------------------------------------------- +* +* Emulation -- Set Processor into "emulation" mode. +* + +Emulation MAC + SEC + XCE + EOM + +*----------------------------------------------------- +* +* WriteCh -- Print Character From Accumulator +* WriteCh ADDR -- Print Character At Label +* WriteCh ADDR,X -- Print Character At Label,X +* + +WriteCh MAC + DO ]0 + LDA ]1 + FIN + PHA + LDX #$180C + JSL $E10000 + EOM + +*----------------------------------------------------- +* +* ReadCh -- Get Keypress in Accumulator +* ReadCh ADDR -- Get Keypress in Label +* + +ReadCh MAC + PEA 0 + PEA 1 + LDX #$220C + JSL $E10000 + PLA + DO ]0 + STA ]1 + FIN + EOM + +*----------------------------------------------------- +* +* WriteLn "STRING" -- Print Literal String with CR. +* WriteLn ADDR -- Print String At Address with CR. +* WriteLn -- Print CR. +* + +WriteLn MAC + DO ]0 + WriteStr ]1 + FIN + WriteCh #$8D + EOM + +*----------------------------------------------------- +* +* WriteStr "STRING" -- Print Literal String. +* WriteStr ADDR -- Print String At Address. +* WriteStr -- Print String At A (Lo),Y (Hi). +* + +WriteStr MAC + IF 0=]0 ;If No Label + PHY + PHA + + ELSE + + IF "=]1 + PEA ^]String + PEA ]String + BRL ]Skip +]String STR ]1 +]Skip + ELSE + + IF '=]1 + PEA ^]String + PEA ]String + BRL ]Skip +]String STR ]1 +]Skip + ELSE + + PEA ^]1 + PEA ]1 + + FIN + FIN + FIN + LDX #$1C0C + JSL $E10000 + EOM + +*----------------------------------------------------- +* +* DrawStrHV 8;12;"STRING" Print Literal String on +* DrawStr 8;12;ADDR Super Hi-Res Screen. +* + +DrawStrHV MAC + HtabVtab ]1;]2 + DrawStr ]3 + <<< + +*----------------------------------------------------- +* +* DrawStr "STRING" -- Print Literal String. +* DrawStr ADDR -- Print String At Address. +* + +DrawStr MAC + IF "=]1 + PEA ^]String + PEA ]String + BRL ]Skip +]String STR ]1 +]Skip + ELSE + IF '=]1 + PEA ^]String + PEA ]String + BRL ]Skip +]String STR ]1 +]Skip + ELSE + PEA ^]1 + PEA ]1 + FIN + FIN + LDX #$A504 ;DrawString + JSL $E10000 + <<< + +*----------------------------------------------------- +* +* HtabVtab #8;#12 -- Position at Htab 8, Vtab 12. +* HtabVtab H;V on super hires screens. +* + +HtabVtab MAC + IF #=]1 + LDA ]1*8 + ELSE + LDA ]1 + ASL + ASL + ASL + FIN + PHA + IF #=]1 + LDA ]2*8 + ELSE + LDA ]2 + ASL + ASL + ASL + FIN + PHA + LDX #$3A04 ;MoveTo + JSL $E10000 + <<< + +*----------------------------------------------------- +* +* Deref MyHandle;MyPtr -- Uses zero page 0-3 to +* de-reference a handle. +* + +Deref MAC + LDA ]1 + LDX ]1+2 + STA 0 + STX 2 + LDA [0] + STA ]2 + LDY #2 + LDA [0],Y + STA ]2+2 + <<< + +*================================================== +* The MLI16 macro assumes the CALLDOS file from the +* SUBROUT.LIB is linked in. It provides an easy +* way to make MLI calls. Example syntax: +* +* MLI16 close;CLSPARMS +*-------------------------------------------------- + +MLI16 MAC ;Uses CALLDOS file in the + IF MX ; subroutine library + REP %00110000 ;Force full 16-bit mode, if + FIN ; not already there. + LDX #]1 ;Call code (use MLI.CODES) + LDA #]2 ;Low word of PARMS tbl adr + JSR CALLDOS ;Returns CS if an error + <<< + +*================================================= +* The following macros are APW-equivalents for +* compatibility with APW style listings. +* +* One difference between Merlin and APW here: Instead of +* using the syntax PULL1 ADDRESS;X, Merlin can take +* the raw statement PULL1 ADDRESS,X. +* + +PULL1 MAC + SEP #%00100000 + PLA + REP #%00100000 + DO ]0/1 ;If 1 parm + IF MX>0 + STA ]1 + FIN + IF MX=0 + STAL ]1 + FIN + FIN + <<< + +PULL3 MAC + SEP #%00100000 + PLA + STA ]1 + REP #%00100000 + PLA + STA ]1+1 + FIN + <<< + +PUSH1 MAC + SEP #%00100000 + IF ]0/1 ;if one parm + LDA ]1 + FIN + PHA + REP #%00100000 + <<< + +PUSH3 MAC + IF #=]1 + LDA #^]1 ;get two hi order bytes + PHA + PHB + LDA #<]1 + STA 1,S + ELSE + LDA ]1+1 + PHA + PHB + LDA ]1 + STA 1,S + FIN + <<< + diff --git a/Library/VGA.Macs.s b/Library/VGA.Macs.s new file mode 100644 index 0000000..2b2350f --- /dev/null +++ b/Library/VGA.Macs.s @@ -0,0 +1,66 @@ +* +* Macros SecondSight +* +* (c) 1995, Brutal Deluxe +* + +_SSGetStatus MAC + jsl _xGetStatus + <<< + +_SSSetMode MAC + jsl _xSetMode + <<< + +_SSUploadData MAC + jsl _xUploadData + <<< + +_SSScrollScreen MAC + jsl _xScrollScreen + <<< + +_SSScreenOff MAC + jsl _xScreenOff + <<< + +_SSScreenOn MAC + jsl _xScreenOn + <<< + +_SSSetPalette MAC + jsl _xSetPalette + <<< + +_SSSetPaletteEntry MAC + jsl _xSetPaletteEntry + <<< + +_SSSetBorder MAC + jsl _xSetBorder + <<< + +_SSRunCode MAC + jsl _xRunCode + <<< + +_SSClearScreen MAC + jsl _xClearScreen + <<< + +_SSSetShadow MAC + jsl _xSetShadow + <<< + +_SSSetVGAReg MAC + jsl _xSetVGAReg + <<< + +_SSGetVGAReg MAC + jsl _xGetVGAReg + <<< + +_SSSetUserMode MAC + jsl _xSetUserMode + <<< + diff --git a/Library/Video.Macs.s b/Library/Video.Macs.s new file mode 100644 index 0000000..58abb5e --- /dev/null +++ b/Library/Video.Macs.s @@ -0,0 +1,89 @@ +* +* Video Overlay tool calls +* + +_VDBootInit mac + Tool $0121 + <<< +_VDStartUp mac + Tool $0221 + <<< +_VDShutDown mac + Tool $0321 + <<< +_VDVersion mac + Tool $0421 + <<< +_VDReset mac + Tool $0521 + <<< +_VDStatus mac + Tool $0621 + <<< +_VDInStatus mac + Tool $0921 + <<< +_VDInSetStd mac + Tool $0a21 + <<< +_VDInGetStd mac + Tool $0b21 + <<< +_VDInConvAdj mac + Tool $0c21 + <<< +_VDKeyControl mac + Tool $0d21 + <<< +_VDKeyStatus mac + Tool $0e21 + <<< +_VDKeySetKCol mac + Tool $0f21 + <<< +_VDKeyGetKRCol mac + Tool $1021 + <<< +_VDKeyGetKGCol mac + Tool $1121 + <<< +_VDKeyGetKBCol mac + Tool $1221 + <<< +_VDKeySetKDiss mac + Tool $1321 + <<< +_VDKeyGetKDiss mac + Tool $1421 + <<< +_VDKeySetNKDiss mac + Tool $1521 + <<< +_VDKeyGetNKDiss mac + Tool $1621 + <<< +_VDOutSetStd mac + Tool $1721 + <<< +_VDOutGetStd mac + Tool $1821 + <<< +_VDOutControl mac + Tool $1921 + <<< +_VDOutStatus mac + Tool $1a21 + <<< +_VDGetFeatures mac + Tool $1b21 + <<< +_VDInControl mac + Tool $1c21 + <<< +_VDGGControl mac + Tool $1d21 + <<< +_VDGGStatus mac + Tool $1e21 + <<< + diff --git a/Library/Window.Macs.s b/Library/Window.Macs.s new file mode 100644 index 0000000..1c8b346 --- /dev/null +++ b/Library/Window.Macs.s @@ -0,0 +1,537 @@ +* Window Manager macros +* by Dave Klimas +; +; Copyright Apple Computer, Inc. 1986, 1987 +; and Roger Wagner Publishing, Inc. 1988 +; All Rights Reserved +; +_WindBootInit MAC + Tool $10E + <<< +~WindStartUp MAC + PHW ]1 +_WindStartUp MAC + Tool $20E + <<< +_WindShutDown MAC + Tool $30E + <<< +~WindVersion MAC + PHA +_WindVersion MAC + Tool $40E + <<< +_WindReset MAC + Tool $50E + <<< +~WindStatus MAC + PHA +_WindStatus MAC + Tool $60E + <<< +~NewWindow MAC + P2SL ]1 +_NewWindow MAC + Tool $90E + <<< +~CheckUpdate MAC + P1SL ]1 +_CheckUpdate MAC + Tool $A0E + <<< +~CloseWindow MAC + PHL ]1 +_CloseWindow MAC + Tool $B0E + <<< +~Desktop MAC + IF 2=]1 + IF 3=]1 + IF 4=]1 + PHS 2 + FIN + FIN + FIN + PHWL ]1;]2 +_Desktop MAC + Tool $C0E + <<< +~SetWTitle MAC + PxL ]1;]2 +_SetWTitle MAC + Tool $D0E + <<< +~GetWTitle MAC + P2SL ]1 +_GetWTitle MAC + Tool $E0E + <<< +~SetFrameColor MAC + PxL ]1;]2 +_SetFrameColor MAC + Tool $F0E + <<< +~GetFrameColor MAC + PxL ]1;]2 +_GetFrameColor MAC + Tool $100E + <<< +~SelectWindow MAC + PHL ]1 +_SelectWindow MAC + Tool $110E + <<< +~HideWindow MAC + PHL ]1 +_HideWindow MAC + Tool $120E + <<< +~ShowWindow MAC + PHL ]1 +_ShowWindow MAC + Tool $130E + <<< +~SendBehind MAC + PxL ]1;]2 +_SendBehind MAC + Tool $140E + <<< +~FrontWindow MAC + PHS 2 +_FrontWindow MAC + Tool $150E + <<< +~SetInfoDraw MAC + PxL ]1;]2 +_SetInfoDraw MAC + Tool $160E + <<< +~FindWindow MAC + P1SL ]1 + PxW ]2;]3 +_FindWindow MAC + Tool $170E + <<< +~TrackGoAway MAC + P1SW ]1 + PHWL ]2;]3 +_TrackGoAway MAC + Tool $180E + <<< +~MoveWindow MAC + PxW ]1;]2 + PHL ]3 +_MoveWindow MAC + Tool $190E + <<< +~DragWindow MAC + PxW ]1;]2;]3;]4 + PxL ]5;]6 +_DragWindow MAC + Tool $1A0E + <<< +~GrowWindow MAC + PHS 2 + PxW ]1;]2;]3;]4 + PHL ]5 +_GrowWindow MAC + Tool $1B0E + <<< +~SizeWindow MAC + PxW ]1;]2 + PHL ]3 +_SizeWindow MAC + Tool $1C0E + <<< +~TaskMaster MAC + PHA + PHWL ]1;]2 +_TaskMaster MAC + Tool $1D0E + <<< +~BeginUpdate MAC + PHL ]1 +_BeginUpdate MAC + Tool $1E0E + <<< +~EndUpdate MAC + PHL ]1 +_EndUpdate MAC + Tool $1F0E + <<< +~GetWMgrPort MAC + PHS 2 +_GetWMgrPort MAC + Tool $200E + <<< +~PinRect MAC + PHS 2 + PxW ]1;]2 + PHL ]3 +_PinRect MAC + Tool $210E + <<< +~HiliteWindow MAC + PHWL ]1;]2 +_HiliteWindow MAC + Tool $220E + <<< +~ShowHide MAC + PHWL ]1;]2 +_ShowHide MAC + Tool $230E + <<< +~BringToFront MAC + PHL ]1 +_BringToFront MAC + Tool $240E + <<< +_WindNewRes MAC + Tool $250E + <<< +~TrackZoom MAC + P1SW ]1 + PHWL ]2;]3 +_TrackZoom MAC + Tool $260E + <<< +~ZoomWindow MAC + PHL ]1 +_ZoomWindow MAC + Tool $270E + <<< +~SetWRefCon MAC + PxL ]1;]2 +_SetWRefCon MAC + Tool $280E + <<< +~GetWRefCon MAC + P2SL ]1 +_GetWRefCon MAC + Tool $290E + <<< +~GetNextWindow MAC + P2SL ]1 +_GetNextWindow MAC + Tool $2A0E + <<< +~GetWKind MAC + P1SL ]1 +_GetWKind MAC + Tool $2B0E + <<< +~SetWFrame MAC + PHWL ]1;]2 +_SetWFrame MAC + Tool $2D0E + <<< +~GetWFrame MAC + P1SL ]1 +_GetWFrame MAC + Tool $2C0E + <<< +~GetStructRgn MAC + P2SL ]1 +_GetStructRgn MAC + Tool $2E0E + <<< +~GetContentRgn MAC + P2SL ]1 +_GetContentRgn MAC + Tool $2F0E + <<< +~GetUpdateRgn MAC + P2SL ]1 +_GetUpdateRgn MAC + Tool $300E + <<< +~GetDefProc MAC + P2SL ]1 +_GetDefProc MAC + Tool $310E + <<< +~SetDefProc MAC + PxL ]1;]2 +_SetDefProc MAC + Tool $320E + <<< +~GetWControls MAC + P2SL ]1 +_GetWControls MAC + Tool $330E + <<< +~SetOriginMask MAC + PHWL ]1;]2 +_SetOriginMask MAC + Tool $340E + <<< +~GetInfoRefCon MAC + P2SL ]1 +_GetInfoRefCon MAC + Tool $350E + <<< +~SetInfoRefCon MAC + PxL ]1;]2 +_SetInfoRefCon MAC + Tool $360E + <<< +~GetZoomRect MAC + P2SL ]1 +_GetZoomRect MAC + Tool $370E + <<< +~SetZoomRect MAC + PxL ]1;]2 +_SetZoomRect MAC + Tool $380E + <<< +~RefreshDesktop MAC + PHL ]1 +_RefreshDesktop MAC + Tool $390E + <<< +~InvalRect MAC + PHL ]1 +_InvalRect MAC + Tool $3A0E + <<< +~InvalRgn MAC + PHL ]1 +_InvalRgn MAC + Tool $3B0E + <<< +~ValidRect MAC + PHL ]1 +_ValidRect MAC + Tool $3C0E + <<< +~ValidRgn MAC + PHL ]1 +_ValidRgn MAC + Tool $3D0E + <<< +~GetContentOrigin MAC + P2SL ]1 +_GetContentOrigin MAC + Tool $3E0E + <<< +~SetContentOrigin MAC + PxW ]1;]2 + PHL ]3 +_SetContentOrigin MAC + Tool $3F0E + <<< +~GetDataSize MAC + P2SL ]1 +_GetDataSize MAC + Tool $400E + <<< +~SetDataSize MAC + PxW ]1;]2 + PHL ]3 +_SetDataSize MAC + Tool $410E + <<< +~GetMaxGrow MAC + P2SL ]1 +_GetMaxGrow MAC + Tool $420E + <<< +~SetMaxGrow MAC + PxW ]1;]2 + PHL ]3 +_SetMaxGrow MAC + Tool $430E + <<< +~GetScroll MAC + P2SL ]1 +_GetScroll MAC + Tool $440E + <<< +~SetScroll MAC + PxW ]1;]2 + PHL ]3 +_SetScroll MAC + Tool $450E + <<< +~GetPage MAC + P2SL ]1 +_GetPage MAC + Tool $460E + <<< +~SetPage MAC + PxW ]1;]2 + PHL ]3 +_SetPage MAC + Tool $470E + <<< +~GetContentDraw MAC + P2SL ]1 +_GetContentDraw MAC + Tool $480E + <<< +~SetContentDraw MAC + PxL ]1;]2 +_SetContentDraw MAC + Tool $490E + <<< +~GetInfoDraw MAC + P2SL ]1 +_GetInfoDraw MAC + Tool $4A0E + <<< +~SetSysWindow MAC + PHL ]1 +_SetSysWindow MAC + Tool $4B0E + <<< +~GetSysWFlag MAC + P1SL ]1 +_GetSysWFlag MAC + Tool $4C0E + <<< +~StartDrawing MAC + PHL ]1 +_StartDrawing MAC + Tool $4D0E + <<< +~SetWindowIcons MAC + P2SL ]1 +_SetWindowIcons MAC + Tool $4E0E + <<< +~GetRectInfo MAC + PxL ]1;]2 +_GetRectInfo MAC + Tool $4F0E + <<< +~StartInfoDrawing MAC + PxL ]1;]2 +_StartInfoDrawing MAC + Tool $500E + <<< +_EndInfoDrawing MAC + Tool $510E + <<< +~GetFirstWindow MAC + PHS 2 +_GetFirstWindow MAC + Tool $520E + <<< +~WindDragRect MAC + P2SL ]1 + PHLW ]2;]3 + PHWL ]4;]5 + PxL ]6;]7 + PHW ]8 +_WindDragRect MAC + Tool $530E + <<< +_Private01 MAC + Tool $540E + <<< +~DrawInfoBar MAC + PHL ]1 +_DrawInfoBar MAC + Tool $550E + <<< +~WindowGlobal MAC + P1SW ]1 +_WindowGlobal MAC + Tool $560E + <<< +~SetContentOrigin2 MAC + PxW ]1;]2;]3 + PHL ]4 +_SetContentOrigin2 MAC + Tool $570E + <<< +~GetWindowMgrGlobals MAC + PHS 2 +_GetWindowMgrGlobals MAC + Tool $580E + <<< +~AlertWindow MAC + P1SW ]1 + PxL ]2;]3 +_AlertWindow MAC + Tool $590E + <<< +~StartFrameDrawing MAC + PHL ]1 +_StartFrameDrawing MAC + Tool $5A0E + <<< +_EndFrameDrawing MAC + Tool $5B0E + <<< +~ResizeWindow MAC + PHWL ]1;]2 + PHL ]3 +_ResizeWindow MAC + Tool $5C0E + <<< +_TaskMasterContent MAC ;private + Tool $5D0E + <<< +_TaskMasterKey MAC ;private + Tool $5E0E + <<< +~TaskMasterDA MAC + P1SW ]1 + PHL ]2 +_TaskMasterDA MAC + Tool $5F0E + <<< +~CompileText MAC + P2SW ]1 + PxL ]2;]3 + PHW ]4 +_CompileText MAC + Tool $600E + <<< +~NewWindow2 MAC + PHS 2 + PxL ]1;]2;]3;]4 + PHWL ]5;]6 + PHW ]7 +_NewWindow2 MAC + Tool $610E + <<< +~ErrorWindow MAC + P1SW ]1 + PHLW ]2;]3 +_ErrorWindow MAC + Tool $620E + <<< +_GetAuxWindInfo MAC + Tool $630E + <<< +_DoModalWindow MAC + Tool $640E + <<< +_MWGetCtlPart MAC + Tool $650E + <<< +_MWSetMenuProc MAC + Tool $660E + <<< +_MWStdDrawProc MAC + Tool $670E + <<< +_MWSetUpEditMenu MAC + Tool $680E + <<< +_FindCursorCtl MAC + Tool $690E + <<< +_ResizeInfoBar MAC + Tool $6A0E + <<< +_HandleDiskInsert MAC + Tool $6B0E + <<< +_UpdateWindow MAC + Tool $6C0E + <<< + diff --git a/Source/Dc_Library.c b/Source/Dc_Library.c new file mode 100644 index 0000000..c18321a --- /dev/null +++ b/Source/Dc_Library.c @@ -0,0 +1,5397 @@ +/***********************************************************************/ +/* */ +/* Dc_Library.c : Module pour la bibliothèque générique de fonctions. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +/** Platform dependent code **/ +#if defined(WIN32) || defined(WIN64) +/* Windows */ +#include +#include /* GetFileAttributes() SetFileAttributes() FILE_ATTRIBUTE_HIDDEN */ +#else +/* Linux + MacOS */ +#include +#include /* strcasecmp() strncasecmp() */ +#include /* unlink() */ +#include +#include +#endif + +#include "Dc_Library.h" +#include "a65816_Macro.h" +#include "a65816_File.h" +#include "a65816_Line.h" +#include "a65816_OMF.h" + +int compare_item(const void *,const void *); +int compare_macro(const void *,const void *); +int compare_label(const void *,const void *); +int compare_equivalence(const void *,const void *); +int compare_variable(const void *,const void *); +int compare_external(const void *,const void *); + +/*********************************************/ +/* my_RaiseError() : Gestion des erreurs. */ +/*********************************************/ +void my_RaiseError(int code, void *data) +{ + static int error_state = ERROR_NOT_READY_YET; + static jmp_buf *context; + static char *error_string; + + switch(code) + { + case ERROR_INIT : + context = (jmp_buf *) data; + error_string = NULL; + error_state = ERROR_READY; + break; + + case ERROR_END : + error_state = ERROR_NOT_READY_YET; + break; + + case ERROR_GET_STRING : + if(error_state == ERROR_READY) + *((char **) data) = error_string; + break; + + default : /* ERROR_RAISE */ + if(error_state == ERROR_READY) + { + /* Construction du message d'erreur utilisateur */ + error_string = strdup((char *) data); + + /* Saut au début du code */ + error_state = ERROR_READY; + longjmp(*context,1); + } + break; + } +} + + +/**************************************************/ +/* my_File() : Gestion des ressources fichiers. */ +/**************************************************/ +void my_File(int code, void *data) +{ + int i; + static long hFile_tab[256]; + + switch(code) + { + case FILE_INIT : + for(i=0; i<256; i++) + hFile_tab[i] = 0; + break; + + case FILE_FREE : + /* Fermeture des Directory */ + for(i=0; i<256; i++) + if(hFile_tab[i] != 0) + { +#if defined(WIN32) || defined(WIN64) + _findclose(hFile_tab[i]); +#endif + hFile_tab[i] = 0; + } + break; + + case FILE_DECLARE_DIRECTORY : + for(i=0; i<256; i++) + if(hFile_tab[i] == 0) + { + hFile_tab[i] = *((long *) data); + break; + } + break; + + case FILE_FREE_DIRECTORY : + for(i=0; i<256; i++) + if(hFile_tab[i] == *((long *) data)) + { + hFile_tab[i] = 0; + break; + } + break; + + default : + break; + } +} + + +/****************************************************/ +/* my_Memory() : Gestion des ressources mémoires. */ +/****************************************************/ +void my_Memory(int code, void *data, void *value, struct omf_segment *current_omfsegment) +{ + int i; + static struct parameter *param; /* Structure Parameter */ + static struct omf_segment *curr_omfsegment; + struct source_file *current_file; /* Fichier source */ + struct source_file *next_file; + struct item *current_opcode; /* Liste des opcode */ + struct item *next_opcode; + struct item *new_opcode; + struct item *current_data; /* Liste des data */ + struct item *next_data; + struct item *new_data; + struct item *current_directive; /* Liste des directive */ + struct item *next_directive; + struct item *new_directive; + struct item *current_direqu; /* Liste des directive equivalence */ + struct item *next_direqu; + struct item *new_direqu; + struct item **found_item_ptr; + struct macro *current_macro; /* Liste des macro */ + struct macro *next_macro; + struct macro **found_macro_ptr; + struct label *current_label; /* Liste des label */ + struct label *next_label; + struct label **found_label_ptr; + struct equivalence *current_equivalence; /* Liste des equivalence */ + struct equivalence *new_equivalence; + struct equivalence *next_equivalence; + struct equivalence **found_equivalence_ptr; + struct variable *current_variable; /* Liste des variable */ + struct variable *next_variable; + struct variable **found_variable_ptr; + struct external *current_external; /* Liste des external */ + struct external *next_external; + struct external **found_external_ptr; + struct global *current_global; /* Liste des global */ + struct global *next_global; + struct global *new_global; + + switch(code) + { + case MEMORY_INIT : + param = NULL; + current_omfsegment = NULL; + break; + + case MEMORY_FREE : + mem_free_param(param); + my_Memory(MEMORY_INIT,NULL,NULL,NULL); + break; + + /*************************/ + /* Structure Parameter */ + /*************************/ + case MEMORY_SET_PARAM : + param = (struct parameter *) data; + break; + + case MEMORY_GET_PARAM : + *((struct parameter **) data) = param; + break; + + /***************************/ + /* Structure OMF Segment */ + /***************************/ + case MEMORY_SET_OMFSEGMENT : + curr_omfsegment = (struct omf_segment *) data; + break; + + case MEMORY_GET_OMFSEGMENT : + *((struct omf_segment **) data) = curr_omfsegment; + break; + + /*************************************/ + /* Déclare les allocation mémoires */ + /*************************************/ + case MEMORY_DECLARE_ALLOC : + for(i=0; i<1024; i++) + if(current_omfsegment->alloc_table[i] == NULL) + { + current_omfsegment->alloc_table[i] = data; + break; + } + break; + + case MEMORY_FREE_ALLOC : + for(i=0; i<1024; i++) + if(current_omfsegment->alloc_table[i] == data) + { + current_omfsegment->alloc_table[i] = NULL; + break; + } + break; + + /********************/ + /* Structure File */ + /********************/ + case MEMORY_SET_FILE : + current_omfsegment->first_file = (struct source_file *) data; + break; + + case MEMORY_GET_FILE : + *((struct source_file **) data) = current_omfsegment->first_file; + break; + + case MEMORY_FREE_FILE : + for(current_file = current_omfsegment->first_file; current_file; ) + { + next_file = current_file->next; + mem_free_sourcefile(current_file,(current_file==current_omfsegment->first_file)?1:0); + current_file = next_file; + } + break; + + /*****************/ + /* Opcode List */ + /*****************/ + case MEMORY_ADD_OPCODE : + /* Déjà présent ? */ + for(current_opcode = current_omfsegment->first_opcode; current_opcode; current_opcode = current_opcode->next) + if(!my_stricmp(current_opcode->name,(char *) data)) + return; + + /* Allocation mémoire */ + new_opcode = (struct item *) calloc(1,sizeof(struct item)); + if(new_opcode == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for structure item (opcode)"); + new_opcode->name = strdup((char *) data); + if(new_opcode->name == NULL) + { + free(new_opcode); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for 'name' from structure item (opcode)"); + } + + /* Attache la structure */ + if(current_omfsegment->first_opcode == NULL) + current_omfsegment->first_opcode = new_opcode; + else + current_omfsegment->last_opcode->next = new_opcode; + current_omfsegment->last_opcode = new_opcode; + current_omfsegment->nb_opcode++; + break; + + case MEMORY_GET_OPCODE_NB : + *((int *) data) = current_omfsegment->nb_opcode; + break; + + case MEMORY_GET_OPCODE : + /* Init */ + *((char **)value) = NULL; + + /* Vérification d'un dépassement */ + if(*((int *)data) <= 0 || *((int *)data) > current_omfsegment->nb_opcode) + return; + + /* Accès direct par le tableau */ + if(current_omfsegment->tab_opcode) + { + *((char **)value) = current_omfsegment->tab_opcode[(*((int *)data))-1]->name; + return; + } + + /* Localise la strucure */ + for(i=0,current_opcode=current_omfsegment->first_opcode; i<(*((int *)data))-1; i++) + current_opcode = current_opcode->next; + *((char **)value) = current_opcode->name; + break; + + case MEMORY_SORT_OPCODE : + if(current_omfsegment->nb_opcode == 0) + return; + + /* Allocation mémoire */ + if(current_omfsegment->tab_opcode) + free(current_omfsegment->tab_opcode); + current_omfsegment->tab_opcode = (struct item **) calloc(current_omfsegment->nb_opcode,sizeof(struct item *)); + if(current_omfsegment->tab_opcode == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for tab_opcode table"); + + /* Place les item */ + for(i=0,current_opcode=current_omfsegment->first_opcode; current_opcode; current_opcode=current_opcode->next,i++) + current_omfsegment->tab_opcode[i] = current_opcode; + + /* Tri */ + qsort(current_omfsegment->tab_opcode,current_omfsegment->nb_opcode,sizeof(struct item *),compare_item); + + /* Replace les liens */ + for(i=0; inb_opcode; i++) + { + if(i == current_omfsegment->nb_opcode-1) + current_omfsegment->tab_opcode[i]->next = NULL; + else + current_omfsegment->tab_opcode[i]->next = current_omfsegment->tab_opcode[i+1]; + } + current_omfsegment->first_opcode = current_omfsegment->tab_opcode[0]; + current_omfsegment->last_opcode = current_omfsegment->tab_opcode[current_omfsegment->nb_opcode-1]; + break; + + case MEMORY_SEARCH_OPCODE : + /* Init */ + *((struct item **)value) = NULL; + + /** Recherche par le tableau **/ + if(current_omfsegment->tab_opcode != NULL) + { + current_omfsegment->local_item.name = (char *) data; + found_item_ptr = (struct item **) bsearch(¤t_omfsegment->local_item_ptr,(void *)current_omfsegment->tab_opcode,current_omfsegment->nb_opcode,sizeof(struct item *),compare_item); + if(found_item_ptr != NULL) + *((struct item **)value) = *found_item_ptr; + } + break; + + case MEMORY_FREE_OPCODE : + for(current_opcode = current_omfsegment->first_opcode; current_opcode; ) + { + next_opcode = current_opcode->next; + mem_free_item(current_opcode); + current_opcode = next_opcode; + } + current_omfsegment->nb_opcode = 0; + current_omfsegment->first_opcode = NULL; + current_omfsegment->last_opcode = NULL; + if(current_omfsegment->tab_opcode) + free(current_omfsegment->tab_opcode); + current_omfsegment->tab_opcode = NULL; + break; + + + /***************/ + /* Data List */ + /***************/ + case MEMORY_ADD_DATA : + /* Déjà présent ? */ + for(current_data = current_omfsegment->first_data; current_data; current_data = current_data->next) + if(!my_stricmp(current_data->name,(char *) data)) + return; + + /* Allocation mémoire */ + new_data = (struct item *) calloc(1,sizeof(struct item)); + if(new_data == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for structure item (data)"); + new_data->name = strdup((char *) data); + if(new_data->name == NULL) + { + free(new_data); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for 'name' from structure item (data)"); + } + + /* Attache la structure */ + if(current_omfsegment->first_data == NULL) + current_omfsegment->first_data = new_data; + else + current_omfsegment->last_data->next = new_data; + current_omfsegment->last_data = new_data; + current_omfsegment->nb_data++; + break; + + case MEMORY_GET_DATA_NB : + *((int *) data) = current_omfsegment->nb_data; + break; + + case MEMORY_GET_DATA : + /* Init */ + *((char **)value) = NULL; + + /* Vérification d'un dépassement */ + if(*((int *)data) <= 0 || *((int *)data) > current_omfsegment->nb_data) + return; + + /* Accès direct par le tableau */ + if(current_omfsegment->tab_data) + { + *((char **)value) = current_omfsegment->tab_data[(*((int *)data))-1]->name; + return; + } + + /* Localise la strucure */ + for(i=0,current_data=current_omfsegment->first_data; i<(*((int *)data))-1; i++) + current_data = current_data->next; + *((char **)value) = current_data->name; + break; + + case MEMORY_SORT_DATA : + if(current_omfsegment->nb_data == 0) + return; + + /* Allocation mémoire */ + if(current_omfsegment->tab_data) + free(current_omfsegment->tab_data); + current_omfsegment->tab_data = (struct item **) calloc(current_omfsegment->nb_data,sizeof(struct item *)); + if(current_omfsegment->tab_data == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for tab_data table"); + + /* Place les item */ + for(i=0,current_data=current_omfsegment->first_data; current_data; current_data=current_data->next,i++) + current_omfsegment->tab_data[i] = current_data; + + /* Tri */ + qsort(current_omfsegment->tab_data,current_omfsegment->nb_data,sizeof(struct item *),compare_item); + + /* Replace les liens */ + for(i=0; inb_data; i++) + { + if(i == current_omfsegment->nb_data-1) + current_omfsegment->tab_data[i]->next = NULL; + else + current_omfsegment->tab_data[i]->next = current_omfsegment->tab_data[i+1]; + } + current_omfsegment->first_data = current_omfsegment->tab_data[0]; + current_omfsegment->last_data = current_omfsegment->tab_data[current_omfsegment->nb_data-1]; + break; + + case MEMORY_SEARCH_DATA : + /* Init */ + *((struct item **)value) = NULL; + + /** Recherche par le tableau **/ + if(current_omfsegment->tab_data != NULL) + { + current_omfsegment->local_item.name = (char *) data; + found_item_ptr = (struct item **) bsearch(¤t_omfsegment->local_item_ptr,(void *)current_omfsegment->tab_data,current_omfsegment->nb_data,sizeof(struct item *),compare_item); + if(found_item_ptr != NULL) + *((struct item **)value) = *found_item_ptr; + } + break; + + case MEMORY_FREE_DATA : + for(current_data = current_omfsegment->first_data; current_data; ) + { + next_data = current_data->next; + mem_free_item(current_data); + current_data = next_data; + } + current_omfsegment->nb_data = 0; + current_omfsegment->first_data = NULL; + current_omfsegment->last_data = NULL; + if(current_omfsegment->tab_data) + free(current_omfsegment->tab_data); + current_omfsegment->tab_data = NULL; + break; + + + /********************/ + /* Directive List */ + /********************/ + case MEMORY_ADD_DIRECTIVE : + /* Déjà présent ? */ + for(current_directive = current_omfsegment->first_directive; current_directive; current_directive = current_directive->next) + if(!my_stricmp(current_directive->name,(char *) data)) + return; + + /* Allocation mémoire */ + new_directive = (struct item *) calloc(1,sizeof(struct item)); + if(new_directive == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for structure item (directive)"); + new_directive->name = strdup((char *) data); + if(new_directive->name == NULL) + { + free(new_directive); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for 'name' from structure item (directive)"); + } + + /* Attache la structure */ + if(current_omfsegment->first_directive == NULL) + current_omfsegment->first_directive = new_directive; + else + current_omfsegment->last_directive->next = new_directive; + current_omfsegment->last_directive = new_directive; + current_omfsegment->nb_directive++; + break; + + case MEMORY_GET_DIRECTIVE_NB : + *((int *) data) = current_omfsegment->nb_directive; + break; + + case MEMORY_GET_DIRECTIVE : + /* Init */ + *((char **)value) = NULL; + + /* Vérification d'un dépassement */ + if(*((int *)data) <= 0 || *((int *)data) > current_omfsegment->nb_directive) + return; + + /* Accès direct par le tableau */ + if(current_omfsegment->tab_directive) + { + *((char **)value) = current_omfsegment->tab_directive[(*((int *)data))-1]->name; + return; + } + + /* Localise la strucure */ + for(i=0,current_directive=current_omfsegment->first_directive; i<(*((int *)data))-1; i++) + current_directive = current_directive->next; + *((char **)value) = current_directive->name; + break; + + case MEMORY_SORT_DIRECTIVE : + if(current_omfsegment->nb_directive == 0) + return; + + /* Allocation mémoire */ + if(current_omfsegment->tab_directive) + free(current_omfsegment->tab_directive); + current_omfsegment->tab_directive = (struct item **) calloc(current_omfsegment->nb_directive,sizeof(struct item *)); + if(current_omfsegment->tab_directive == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for tab_directive table"); + + /* Place les item */ + for(i=0,current_directive=current_omfsegment->first_directive; current_directive; current_directive=current_directive->next,i++) + current_omfsegment->tab_directive[i] = current_directive; + + /* Tri */ + qsort(current_omfsegment->tab_directive,current_omfsegment->nb_directive,sizeof(struct item *),compare_item); + + /* Replace les liens */ + for(i=0; inb_directive; i++) + { + if(i == current_omfsegment->nb_directive-1) + current_omfsegment->tab_directive[i]->next = NULL; + else + current_omfsegment->tab_directive[i]->next = current_omfsegment->tab_directive[i+1]; + } + current_omfsegment->first_directive = current_omfsegment->tab_directive[0]; + current_omfsegment->last_directive = current_omfsegment->tab_directive[current_omfsegment->nb_directive-1]; + break; + + case MEMORY_SEARCH_DIRECTIVE : + /* Init */ + *((struct item **)value) = NULL; + + /** Recherche par le tableau **/ + if(current_omfsegment->tab_directive != NULL) + { + current_omfsegment->local_item.name = (char *) data; + found_item_ptr = (struct item **) bsearch(¤t_omfsegment->local_item_ptr,(void *)current_omfsegment->tab_directive,current_omfsegment->nb_directive,sizeof(struct item *),compare_item); + if(found_item_ptr != NULL) + *((struct item **)value) = *found_item_ptr; + } + break; + + case MEMORY_FREE_DIRECTIVE : + for(current_directive = current_omfsegment->first_directive; current_directive; ) + { + next_directive = current_directive->next; + mem_free_item(current_directive); + current_directive = next_directive; + } + current_omfsegment->nb_directive = 0; + current_omfsegment->first_directive = NULL; + current_omfsegment->last_directive = NULL; + if(current_omfsegment->tab_directive) + free(current_omfsegment->tab_directive); + current_omfsegment->tab_directive = NULL; + break; + + /********************************/ + /* Directive Equivalence List */ + /********************************/ + case MEMORY_ADD_DIREQU : + /* Déjà présent ? */ + for(current_direqu = current_omfsegment->first_direqu; current_direqu; current_direqu = current_direqu->next) + if(!my_stricmp(current_direqu->name,(char *) data)) + return; + + /* Allocation mémoire */ + new_direqu = (struct item *) calloc(1,sizeof(struct item)); + if(new_direqu == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for structure item (equivalence)"); + new_direqu->name = strdup((char *) data); + if(new_direqu->name == NULL) + { + free(new_direqu); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for 'name' from structure item (equivalence)"); + } + + /* Attache la structure */ + if(current_omfsegment->first_direqu == NULL) + current_omfsegment->first_direqu = new_direqu; + else + current_omfsegment->last_direqu->next = new_direqu; + current_omfsegment->last_direqu = new_direqu; + current_omfsegment->nb_direqu++; + break; + + case MEMORY_GET_DIREQU_NB : + *((int *) data) = current_omfsegment->nb_direqu; + break; + + case MEMORY_GET_DIREQU : + /* Init */ + *((char **)value) = NULL; + + /* Vérification d'un dépassement */ + if(*((int *)data) <= 0 || *((int *)data) > current_omfsegment->nb_direqu) + return; + + /* Accès direct par le tableau */ + if(current_omfsegment->tab_direqu) + { + *((char **)value) = current_omfsegment->tab_direqu[(*((int *)data))-1]->name; + return; + } + + /* Localise la strucure */ + for(i=0,current_direqu=current_omfsegment->first_direqu; i<(*((int *)data))-1; i++) + current_direqu = current_direqu->next; + *((char **)value) = current_direqu->name; + break; + + case MEMORY_SORT_DIREQU : + if(current_omfsegment->nb_direqu == 0) + return; + + /* Allocation mémoire */ + if(current_omfsegment->tab_direqu) + free(current_omfsegment->tab_direqu); + current_omfsegment->tab_direqu = (struct item **) calloc(current_omfsegment->nb_direqu,sizeof(struct item *)); + if(current_omfsegment->tab_direqu == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for tab_direqu table"); + + /* Place les item */ + for(i=0,current_direqu=current_omfsegment->first_direqu; current_direqu; current_direqu=current_direqu->next,i++) + current_omfsegment->tab_direqu[i] = current_direqu; + + /* Tri */ + qsort(current_omfsegment->tab_direqu,current_omfsegment->nb_direqu,sizeof(struct item *),compare_item); + + /* Replace les liens */ + for(i=0; inb_direqu; i++) + { + if(i == current_omfsegment->nb_direqu-1) + current_omfsegment->tab_direqu[i]->next = NULL; + else + current_omfsegment->tab_direqu[i]->next = current_omfsegment->tab_direqu[i+1]; + } + current_omfsegment->first_direqu = current_omfsegment->tab_direqu[0]; + current_omfsegment->last_direqu = current_omfsegment->tab_direqu[current_omfsegment->nb_direqu-1]; + break; + + case MEMORY_SEARCH_DIREQU : + /* Init */ + *((struct item **)value) = NULL; + + /** Recherche par le tableau **/ + if(current_omfsegment->tab_direqu != NULL) + { + current_omfsegment->local_item.name = (char *) data; + found_item_ptr = (struct item **) bsearch(¤t_omfsegment->local_item_ptr,(void *)current_omfsegment->tab_direqu,current_omfsegment->nb_direqu,sizeof(struct item *),compare_item); + if(found_item_ptr != NULL) + *((struct item **)value) = *found_item_ptr; + } + break; + + case MEMORY_FREE_DIREQU : + for(current_direqu = current_omfsegment->first_direqu; current_direqu; ) + { + next_direqu = current_direqu->next; + mem_free_item(current_direqu); + current_direqu = next_direqu; + } + current_omfsegment->nb_direqu = 0; + current_omfsegment->first_direqu = NULL; + current_omfsegment->last_direqu = NULL; + if(current_omfsegment->tab_direqu) + free(current_omfsegment->tab_direqu); + current_omfsegment->tab_direqu = NULL; + break; + + + /******************/ + /* Opcode Macro */ + /******************/ + case MEMORY_ADD_MACRO : + /* Attache la structure */ + if(current_omfsegment->first_macro == NULL) + current_omfsegment->first_macro = (struct macro *) data; + else + current_omfsegment->last_macro->next = (struct macro *) data; + current_omfsegment->last_macro = (struct macro *) data; + current_omfsegment->nb_macro++; + break; + + case MEMORY_GET_MACRO_NB : + *((int *) data) = current_omfsegment->nb_macro; + break; + + case MEMORY_GET_MACRO : + /* Init */ + *((char **)value) = NULL; + + /* Vérification d'un dépassement */ + if(*((int *)data) <= 0 || *((int *)data) > current_omfsegment->nb_macro) + return; + + /* Accès direct par le tableau */ + if(current_omfsegment->tab_macro) + { + *((struct macro **)value) = current_omfsegment->tab_macro[(*((int *)data))-1]; + return; + } + + /* Localise la strucure */ + for(i=0,current_macro=current_omfsegment->first_macro; i<(*((int *)data))-1; i++) + current_macro = current_macro->next; + *((struct macro **)value) = current_macro; + break; + + case MEMORY_SORT_MACRO : + if(current_omfsegment->nb_macro == 0) + return; + + /* Allocation mémoire */ + if(current_omfsegment->tab_macro) + free(current_omfsegment->tab_macro); + current_omfsegment->tab_macro = (struct macro **) calloc(current_omfsegment->nb_macro,sizeof(struct macro *)); + if(current_omfsegment->tab_macro == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for tab_macro table"); + + /* Place les item */ + for(i=0,current_macro=current_omfsegment->first_macro; current_macro; current_macro=current_macro->next,i++) + current_omfsegment->tab_macro[i] = current_macro; + + /* Tri */ + qsort(current_omfsegment->tab_macro,current_omfsegment->nb_macro,sizeof(struct macro *),compare_macro); + + /* Replace les liens */ + for(i=0; inb_macro; i++) + { + if(i == current_omfsegment->nb_macro-1) + current_omfsegment->tab_macro[i]->next = NULL; + else + current_omfsegment->tab_macro[i]->next = current_omfsegment->tab_macro[i+1]; + } + current_omfsegment->first_macro = current_omfsegment->tab_macro[0]; + current_omfsegment->last_macro = current_omfsegment->tab_macro[current_omfsegment->nb_macro-1]; + break; + + case MEMORY_SEARCH_MACRO : + /* Init */ + *((struct macro **)value) = NULL; + + /** Recherche par le tableau **/ + if(current_omfsegment->tab_macro != NULL) + { + current_omfsegment->local_macro.name = (char *) data; + found_macro_ptr = (struct macro **) bsearch(¤t_omfsegment->local_macro_ptr,(void *)current_omfsegment->tab_macro,current_omfsegment->nb_macro,sizeof(struct macro *),compare_macro); + if(found_macro_ptr != NULL) + *((struct macro **)value) = *found_macro_ptr; + } + break; + + case MEMORY_FREE_MACRO : + for(current_macro = current_omfsegment->first_macro; current_macro; ) + { + next_macro = current_macro->next; + mem_free_macro(current_macro); + current_macro = next_macro; + } + current_omfsegment->nb_macro = 0; + current_omfsegment->first_macro = NULL; + current_omfsegment->last_macro = NULL; + if(current_omfsegment->tab_macro) + free(current_omfsegment->tab_macro); + current_omfsegment->tab_macro = NULL; + break; + + + /******************/ + /* Source Label */ + /******************/ + case MEMORY_ADD_LABEL : + /* Attache la structure */ + if(current_omfsegment->first_label == NULL) + current_omfsegment->first_label = (struct label *) data; + else + current_omfsegment->last_label->next = (struct label *) data; + current_omfsegment->last_label = (struct label *) data; + current_omfsegment->nb_label++; + break; + + case MEMORY_GET_LABEL_NB : + *((int *) data) = current_omfsegment->nb_label; + break; + + case MEMORY_GET_LABEL : + /* Init */ + *((char **)value) = NULL; + + /* Vérification d'un dépassement */ + if(*((int *)data) <= 0 || *((int *)data) > current_omfsegment->nb_label) + return; + + /* Accès direct par le tableau */ + if(current_omfsegment->tab_label) + { + *((struct label **)value) = current_omfsegment->tab_label[(*((int *)data))-1]; + return; + } + + /* Localise la strucure */ + for(i=0,current_label=current_omfsegment->first_label; i<(*((int *)data))-1; i++) + current_label = current_label->next; + *((struct label **)value) = current_label; + break; + + case MEMORY_SORT_LABEL : + if(current_omfsegment->nb_label == 0) + return; + + /* Allocation mémoire */ + if(current_omfsegment->tab_label) + free(current_omfsegment->tab_label); + current_omfsegment->tab_label = (struct label **) calloc(current_omfsegment->nb_label,sizeof(struct label *)); + if(current_omfsegment->tab_label == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for tab_label table"); + + /* Place les item */ + for(i=0,current_label=current_omfsegment->first_label; current_label; current_label=current_label->next,i++) + current_omfsegment->tab_label[i] = current_label; + + /* Tri */ + qsort(current_omfsegment->tab_label,current_omfsegment->nb_label,sizeof(struct label *),compare_label); + + /* Replace les liens */ + for(i=0; inb_label; i++) + { + if(i == current_omfsegment->nb_label-1) + current_omfsegment->tab_label[i]->next = NULL; + else + current_omfsegment->tab_label[i]->next = current_omfsegment->tab_label[i+1]; + } + current_omfsegment->first_label = current_omfsegment->tab_label[0]; + current_omfsegment->last_label = current_omfsegment->tab_label[current_omfsegment->nb_label-1]; + break; + + case MEMORY_SEARCH_LABEL : + /* Init */ + *((struct label **)value) = NULL; + + /** Recherche par le tableau **/ + if(current_omfsegment->tab_label != NULL) + { + current_omfsegment->local_label.name = (char *) data; + found_label_ptr = (struct label **) bsearch(¤t_omfsegment->local_label_ptr,(void *)current_omfsegment->tab_label,current_omfsegment->nb_label,sizeof(struct label *),compare_label); + if(found_label_ptr != NULL) + *((struct label **)value) = *found_label_ptr; + } + break; + + case MEMORY_FREE_LABEL : + for(current_label = current_omfsegment->first_label; current_label; ) + { + next_label = current_label->next; + mem_free_label(current_label); + current_label = next_label; + } + current_omfsegment->nb_label = 0; + current_omfsegment->first_label = NULL; + current_omfsegment->last_label = NULL; + if(current_omfsegment->tab_label) + free(current_omfsegment->tab_label); + current_omfsegment->tab_label = NULL; + break; + + + /************************/ + /* Source Equivalence */ + /************************/ + case MEMORY_ADD_EQUIVALENCE : + /* Vérifie l'unicité */ + new_equivalence = (struct equivalence *) data; + for(current_equivalence = current_omfsegment->first_equivalence; current_equivalence; current_equivalence=current_equivalence->next) + { + if(!strcmp(current_equivalence->name,new_equivalence->name) && + current_equivalence->source_line == new_equivalence->source_line) + { + /* Existe déjà */ + mem_free_equivalence(new_equivalence); + return; + } + } + /* Attache la structure */ + if(current_omfsegment->first_equivalence == NULL) + current_omfsegment->first_equivalence = (struct equivalence *) data; + else + current_omfsegment->last_equivalence->next = (struct equivalence *) data; + current_omfsegment->last_equivalence = (struct equivalence *) data; + current_omfsegment->nb_equivalence++; + break; + + case MEMORY_GET_EQUIVALENCE_NB : + *((int *) data) = current_omfsegment->nb_equivalence; + break; + + case MEMORY_GET_EQUIVALENCE : + /* Init */ + *((char **)value) = NULL; + + /* Vérification d'un dépassement */ + if(*((int *)data) <= 0 || *((int *)data) > current_omfsegment->nb_equivalence) + return; + + /* Accès direct par le tableau */ + if(current_omfsegment->tab_equivalence) + { + *((struct equivalence **)value) = current_omfsegment->tab_equivalence[(*((int *)data))-1]; + return; + } + + /* Localise la strucure */ + for(i=0,current_equivalence=current_omfsegment->first_equivalence; i<(*((int *)data))-1; i++) + current_equivalence = current_equivalence->next; + *((struct equivalence **)value) = current_equivalence; + break; + + case MEMORY_SORT_EQUIVALENCE : + if(current_omfsegment->nb_equivalence == 0) + return; + + /* Allocation mémoire */ + if(current_omfsegment->tab_equivalence) + free(current_omfsegment->tab_equivalence); + current_omfsegment->tab_equivalence = (struct equivalence **) calloc(current_omfsegment->nb_equivalence,sizeof(struct equivalence *)); + if(current_omfsegment->tab_equivalence == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for tab_equivalence table"); + + /* Place les item */ + for(i=0,current_equivalence=current_omfsegment->first_equivalence; current_equivalence; current_equivalence=current_equivalence->next,i++) + current_omfsegment->tab_equivalence[i] = current_equivalence; + + /* Tri */ + qsort(current_omfsegment->tab_equivalence,current_omfsegment->nb_equivalence,sizeof(struct equivalence *),compare_equivalence); + + /* Replace les liens */ + for(i=0; inb_equivalence; i++) + { + if(i == current_omfsegment->nb_equivalence-1) + current_omfsegment->tab_equivalence[i]->next = NULL; + else + current_omfsegment->tab_equivalence[i]->next = current_omfsegment->tab_equivalence[i+1]; + } + current_omfsegment->first_equivalence = current_omfsegment->tab_equivalence[0]; + current_omfsegment->last_equivalence = current_omfsegment->tab_equivalence[current_omfsegment->nb_equivalence-1]; + break; + + case MEMORY_SEARCH_EQUIVALENCE : + /* Init */ + *((struct equivalence **)value) = NULL; + + /** Recherche par le tableau **/ + if(current_omfsegment->tab_equivalence != NULL) + { + current_omfsegment->local_equivalence.name = (char *) data; + found_equivalence_ptr = (struct equivalence **) bsearch(¤t_omfsegment->local_equivalence_ptr,(void *)current_omfsegment->tab_equivalence,current_omfsegment->nb_equivalence,sizeof(struct equivalence *),compare_equivalence); + if(found_equivalence_ptr != NULL) + *((struct equivalence **)value) = *found_equivalence_ptr; + } + else + { + /* Recherche via la liste chainée */ + for(current_equivalence=current_omfsegment->first_equivalence; current_equivalence; current_equivalence=current_equivalence->next) + if(!strcmp(current_equivalence->name,(char *)data)) + { + *((struct equivalence **)value) = current_equivalence; + break; + } + } + break; + + case MEMORY_FREE_EQUIVALENCE : + for(current_equivalence = current_omfsegment->first_equivalence; current_equivalence; ) + { + next_equivalence = current_equivalence->next; + mem_free_equivalence(current_equivalence); + current_equivalence = next_equivalence; + } + current_omfsegment->nb_equivalence = 0; + current_omfsegment->first_equivalence = NULL; + current_omfsegment->last_equivalence = NULL; + if(current_omfsegment->tab_equivalence) + free(current_omfsegment->tab_equivalence); + current_omfsegment->tab_equivalence = NULL; + break; + + + /*********************/ + /* Source Variable */ + /*********************/ + case MEMORY_ADD_VARIABLE : + /* Attache la structure */ + if(current_omfsegment->first_variable == NULL) + current_omfsegment->first_variable = (struct variable *) data; + else + current_omfsegment->last_variable->next = (struct variable *) data; + current_omfsegment->last_variable = (struct variable *) data; + current_omfsegment->nb_variable++; + break; + + case MEMORY_GET_VARIABLE_NB : + *((int *) data) = current_omfsegment->nb_variable; + break; + + case MEMORY_GET_VARIABLE : + /* Init */ + *((char **)value) = NULL; + + /* Vérification d'un dépassement */ + if(*((int *)data) <= 0 || *((int *)data) > current_omfsegment->nb_variable) + return; + + /* Accès direct par le tableau */ + if(current_omfsegment->tab_variable) + { + *((struct variable **)value) = current_omfsegment->tab_variable[(*((int *)data))-1]; + return; + } + + /* Localise la strucure */ + for(i=0,current_variable=current_omfsegment->first_variable; i<(*((int *)data))-1; i++) + current_variable = current_variable->next; + *((struct variable **)value) = current_variable; + break; + + case MEMORY_SORT_VARIABLE : + if(current_omfsegment->nb_variable == 0) + return; + + /* Allocation mémoire */ + if(current_omfsegment->tab_variable) + free(current_omfsegment->tab_variable); + current_omfsegment->tab_variable = (struct variable **) calloc(current_omfsegment->nb_variable,sizeof(struct variable *)); + if(current_omfsegment->tab_variable == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for tab_variable table"); + + /* Place les item */ + for(i=0,current_variable=current_omfsegment->first_variable; current_variable; current_variable=current_variable->next,i++) + current_omfsegment->tab_variable[i] = current_variable; + + /* Tri */ + qsort(current_omfsegment->tab_variable,current_omfsegment->nb_variable,sizeof(struct variable *),compare_variable); + + /* Replace les liens */ + for(i=0; inb_variable; i++) + { + if(i == current_omfsegment->nb_variable-1) + current_omfsegment->tab_variable[i]->next = NULL; + else + current_omfsegment->tab_variable[i]->next = current_omfsegment->tab_variable[i+1]; + } + current_omfsegment->first_variable = current_omfsegment->tab_variable[0]; + current_omfsegment->last_variable = current_omfsegment->tab_variable[current_omfsegment->nb_variable-1]; + break; + + case MEMORY_SEARCH_VARIABLE : + /* Init */ + *((struct variable **)value) = NULL; + + /** Recherche par le tableau **/ + if(current_omfsegment->tab_variable != NULL) + { + current_omfsegment->local_variable.name = (char *) data; + found_variable_ptr = (struct variable **) bsearch(¤t_omfsegment->local_variable_ptr,(void *)current_omfsegment->tab_variable,current_omfsegment->nb_variable,sizeof(struct variable *),compare_variable); + if(found_variable_ptr != NULL) + *((struct variable **)value) = *found_variable_ptr; + } + else + { + /* Recherche via la liste chainée */ + for(current_variable=current_omfsegment->first_variable; current_variable; current_variable=current_variable->next) + if(!strcmp(current_variable->name,(char *)data)) + { + *((struct variable **)value) = current_variable; + break; + } + } + break; + + case MEMORY_FREE_VARIABLE : + for(current_variable = current_omfsegment->first_variable; current_variable; ) + { + next_variable = current_variable->next; + mem_free_variable(current_variable); + current_variable = next_variable; + } + current_omfsegment->nb_variable = 0; + current_omfsegment->first_variable = NULL; + current_omfsegment->last_variable = NULL; + if(current_omfsegment->tab_variable) + free(current_omfsegment->tab_variable); + current_omfsegment->tab_variable = NULL; + break; + + /*********************/ + /* Source External */ + /*********************/ + case MEMORY_ADD_EXTERNAL : + /* Attache la structure */ + if(current_omfsegment->first_external == NULL) + current_omfsegment->first_external = (struct external *) data; + else + current_omfsegment->last_external->next = (struct external *) data; + current_omfsegment->last_external = (struct external *) data; + current_omfsegment->nb_external++; + break; + + case MEMORY_GET_EXTERNAL_NB : + *((int *) data) = current_omfsegment->nb_external; + break; + + case MEMORY_GET_EXTERNAL : + /* Init */ + *((char **)value) = NULL; + + /* Vérification d'un dépassement */ + if(*((int *)data) <= 0 || *((int *)data) > current_omfsegment->nb_external) + return; + + /* Accès direct par le tableau */ + if(current_omfsegment->tab_external) + { + *((struct external **)value) = current_omfsegment->tab_external[(*((int *)data))-1]; + return; + } + + /* Localise la strucure */ + for(i=0,current_external=current_omfsegment->first_external; i<(*((int *)data))-1; i++) + current_external = current_external->next; + *((struct external **)value) = current_external; + break; + + case MEMORY_SORT_EXTERNAL : + if(current_omfsegment->nb_external == 0) + return; + + /* Allocation mémoire */ + if(current_omfsegment->tab_external) + free(current_omfsegment->tab_external); + current_omfsegment->tab_external = (struct external **) calloc(current_omfsegment->nb_external,sizeof(struct external *)); + if(current_omfsegment->tab_external == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for tab_external table"); + + /* Place les item */ + for(i=0,current_external=current_omfsegment->first_external; current_external; current_external=current_external->next,i++) + current_omfsegment->tab_external[i] = current_external; + + /* Tri */ + qsort(current_omfsegment->tab_external,current_omfsegment->nb_external,sizeof(struct external *),compare_external); + + /* Replace les liens */ + for(i=0; inb_external; i++) + { + if(i == current_omfsegment->nb_external-1) + current_omfsegment->tab_external[i]->next = NULL; + else + current_omfsegment->tab_external[i]->next = current_omfsegment->tab_external[i+1]; + } + current_omfsegment->first_external = current_omfsegment->tab_external[0]; + current_omfsegment->last_external = current_omfsegment->tab_external[current_omfsegment->nb_external-1]; + break; + + case MEMORY_SEARCH_EXTERNAL : + /* Init */ + *((struct external **)value) = NULL; + + /** Recherche par le tableau **/ + if(current_omfsegment->tab_external != NULL) + { + current_omfsegment->local_external.name = (char *) data; + found_external_ptr = (struct external **) bsearch(¤t_omfsegment->local_external_ptr,(void *)current_omfsegment->tab_external,current_omfsegment->nb_external,sizeof(struct external *),compare_external); + if(found_external_ptr != NULL) + *((struct external **)value) = *found_external_ptr; + } + else + { + /* Recherche via la liste chainée */ + for(current_external=current_omfsegment->first_external; current_external; current_external=current_external->next) + if(!strcmp(current_external->name,(char *)data)) + { + *((struct external **)value) = current_external; + break; + } + } + break; + + case MEMORY_FREE_EXTERNAL : + for(current_external = current_omfsegment->first_external; current_external; ) + { + next_external = current_external->next; + mem_free_external(current_external); + current_external = next_external; + } + current_omfsegment->nb_external = 0; + current_omfsegment->first_external = NULL; + current_omfsegment->last_external = NULL; + if(current_omfsegment->tab_external) + free(current_omfsegment->tab_external); + current_omfsegment->tab_external = NULL; + break; + + /********************************************************************************/ + /* Label ENT qu'il faut recabler car défini sous la forme ENT Labal1,Label2... */ + /********************************************************************************/ + case MEMORY_ADD_GLOBAL : + /* On ne veut pas deux fois le même Label */ + for(current_global = current_omfsegment->first_global; current_global; current_global = current_global->next) + if(!strcmp(current_global->name,(char *)data)) + return; + + /* Allocation mémoire */ + new_global = (struct global *) calloc(1,sizeof(struct global)); + if(new_global == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for global structure"); + new_global->source_line = (struct source_line *) value; + new_global->name = strdup((char *)data); + if(new_global->name == NULL) + { + free(new_global); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for global structure"); + } + + /* Attache la structure */ + if(current_omfsegment->first_global == NULL) + current_omfsegment->first_global = new_global; + else + current_omfsegment->last_global->next = new_global; + current_omfsegment->last_global = new_global; + current_omfsegment->nb_global++; + break; + + case MEMORY_GET_GLOBAL_NB : + *((int *) data) = current_omfsegment->nb_global; + break; + + case MEMORY_GET_GLOBAL : + /* Init */ + *((char **)value) = NULL; + + /* Vérification d'un dépassement */ + if(*((int *)data) <= 0 || *((int *)data) > current_omfsegment->nb_global) + return; + + /* Localise la strucure */ + for(i=0,current_global=current_omfsegment->first_global; i<(*((int *)data))-1; i++) + current_global = current_global->next; + *((struct global **)value) = current_global; + break; + + case MEMORY_FREE_GLOBAL : + for(current_global = current_omfsegment->first_global; current_global; ) + { + next_global = current_global->next; + mem_free_global(current_global); + current_global = next_global; + } + current_omfsegment->nb_global = 0; + current_omfsegment->first_global = NULL; + current_omfsegment->last_global = NULL; + break; + + default : + break; + } +} + + +/**********************************************************/ +/* my_stricmp() : Comparaison de chaines sans la casse. */ +/**********************************************************/ +int my_stricmp(char *string1, char *string2) +{ +#if defined(WIN32) || defined(WIN64) + return(stricmp(string1,string2)); +#else + return(strcasecmp(string1,string2)); +#endif +} + +/***********************************************************/ +/* my_strnicmp() : Comparaison de chaines sans la casse. */ +/***********************************************************/ +int my_strnicmp(char *string1, char *string2, size_t length) +{ +#if defined(WIN32) || defined(WIN64) + return(strnicmp(string1,string2,length)); +#else + return(strncasecmp(string1,string2,length)); +#endif +} + + +/***********************************************/ +/* my_printf64() : Integer 64 bit en string. */ +/***********************************************/ +void my_printf64(int64_t value_64, char *buffer) +{ +#if defined(WIN32) || defined(WIN64) + sprintf(buffer,"%I64d",value_64); +#else + sprintf(buffer,"%" PRId64,value_64); +#endif +} + + +/*********************************************/ +/* my_atoi64() : String en Integer 64 bit. */ +/*********************************************/ +int64_t my_atoi64(char *expression) +{ +#if defined(WIN32) || defined(WIN64) + return(_atoi64(expression)); +#else + return(atoll(expression)); +#endif +} + + +/*****************************************************/ +/* bo_memcpy() : Copie en respectant le Byte order. */ +/*****************************************************/ +void bo_memcpy(void *dst, void *src, size_t nb_byte) +{ + unsigned char data_src[10]; + unsigned char data_dst[10]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /** Classic memcpy for Intel processor (Little Endian) **/ + if(param->byte_order == BYTE_ORDER_INTEL || nb_byte == 1) + memcpy(dst,src,nb_byte); + else + { + /* Change byte order for Big Endian processor */ + memcpy(&data_src[0],src,nb_byte); + + /* 2 Byte */ + if(nb_byte == 2) + { + data_dst[0] = data_src[1]; + data_dst[1] = data_src[0]; + } + /* 4 Byte */ + else if(nb_byte == 4) + { + data_dst[0] = data_src[3]; + data_dst[1] = data_src[2]; + data_dst[2] = data_src[1]; + data_dst[3] = data_src[0]; + } + + /* Copy bytes */ + memcpy(dst,&data_dst[0],nb_byte); + } +} + + +/*******************************************************************/ +/* GetFileProperCasePath() : Recherche un fichier sans sa casse. */ +/*******************************************************************/ +char *GetFileProperCasePath(char *file_path_arg) +{ + int i, is_error, nb_found; + char folder_current[1024]; + char folder_path[1024]; + char file_path[1024]; + char file_name[1024]; + static char file_path_case[1024]; + int nb_file_name; + char **tab_file_name; + + /* Init */ + strcpy(file_path_case,""); + + /** On a besoin d'un chemin absolu **/ +#if defined(WIN32) || defined(WIN64) + if(file_path_arg[1] != ':') + { + /* Répertoire courrant */ + GetCurrentDirectory(1024,folder_current); + if(strlen(folder_current) > 0) + if(folder_current[strlen(folder_current)-1] != '\\') + strcat(folder_current,"\\"); + sprintf(file_path,"%s%s",folder_current,file_path_arg); + } + else + strcpy(file_path,file_path_arg); +#else + if(file_path_arg[0] != '/') + { + /* Répertoire courrant */ + getcwd(folder_current,1024); + if(strlen(folder_current) > 0) + if(folder_current[strlen(folder_current)-1] != '/') + strcat(folder_current,"/"); + sprintf(file_path,"%s%s",folder_current,file_path_arg); + } + else + strcpy(file_path,file_path_arg); +#endif + + /** Récupère le Dossier + Nom du fichier **/ + strcpy(folder_path,file_path); + strcpy(file_name,file_path); + for(i=(int)strlen(folder_path); i>=0; i--) + if(folder_path[i] == '\\' || folder_path[i] == '/') + { + folder_path[i] = '\0'; + strcpy(file_name,&folder_path[i+1]); + break; + } + + /** Liste des fichier du répertoire **/ + tab_file_name = GetFolderFileList(folder_path,&nb_file_name,&is_error); + if(tab_file_name == NULL) + return(NULL); + + /** Recherche le fichier **/ + for(i=0,nb_found=0; i Ambiguité */ + if(nb_found > 1) + return(NULL); + + /* Un seul => OK */ + return(&file_path_case[0]); +} + + +/**************************************************************************/ +/* GetFolderFileList() : Récupère la liste des fichiers d'un répertoire. */ +/**************************************************************************/ +char **GetFolderFileList(char *folder_path, int *nb_file_rtn, int *is_error) +{ +#if defined(WIN32) || defined(WIN64) + int rc; + intptr_t hFile; + int first_time; + struct _finddata_t c_file; +#else + DIR *dp; + struct dirent *dir_entry; +#endif + int nb_item; + struct item *first_item; + struct item *last_item; + struct item *current_item; + struct item *next_item; + int nb_file; + char **tab_file_name; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + *is_error = 0; + nb_file = 0; + tab_file_name = NULL; + nb_item = 0; + first_item = NULL; + last_item = NULL; + + /* Prépare le dossier */ + strcpy(param->buffer_folder_path,folder_path); + if(strlen(param->buffer_folder_path) > 0) + if(param->buffer_folder_path[strlen(param->buffer_folder_path)-1] != '\\' && param->buffer_folder_path[strlen(param->buffer_folder_path)-1] != '/') + strcat(param->buffer_folder_path,FOLDER_SEPARATOR); + +#if defined(WIN32) || defined(WIN64) + /** On boucle sur tous les fichiers présents **/ + sprintf(param->buffer_file_path,"%s*.*",param->buffer_folder_path); + first_time = 1; + while(1) + { + if(first_time == 1) + { + hFile = _findfirst(param->buffer_file_path,&c_file); + rc = (int) hFile; + my_File(FILE_DECLARE_DIRECTORY,&hFile); + } + else + rc = _findnext(hFile,&c_file); + + /* On analyse le résultat */ + if(rc == -1) + break; /* no more files */ + + /** On traite cette entrée **/ + first_time++; + + /* On ignore certaine entrée */ + if((c_file.attrib & _A_SUBDIR) == _A_SUBDIR) + continue; + + /** Garde le fichier **/ + /* Allocation mémoire */ + current_item = (struct item *) calloc(1,sizeof(struct item)); + if(current_item == NULL) + { + my_File(FILE_FREE_DIRECTORY,&hFile); + _findclose(hFile); + /* Libération mémoire */ + for(current_item = first_item; current_item; current_item = next_item) + { + next_item = current_item->next; + if(current_item->name) + free(current_item->name); + free(current_item); + } + *is_error = 1; + return(NULL); + } + current_item->name = strdup(c_file.name); + if(current_item->name == NULL) + { + my_File(FILE_FREE_DIRECTORY,&hFile); + _findclose(hFile); + /* Libération mémoire */ + for(current_item = first_item; current_item; current_item = next_item) + { + next_item = current_item->next; + if(current_item->name) + free(current_item->name); + free(current_item); + } + *is_error = 1; + return(NULL); + } + /* Ajout dans la liste */ + nb_item++; + if(first_item == NULL) + first_item = current_item; + else + last_item->next = current_item; + last_item = current_item; + } + + /* On ferme */ + my_File(FILE_FREE_DIRECTORY,&hFile); + _findclose(hFile); +#else + /* Ouverture du répertoire */ + dp = opendir(folder_path); + if(dp == NULL) + { + *is_error = 1; + return(NULL); + } + + /** Boucle sur tous les fichiers **/ + for(;;) + { + /* Récupère un entrée */ + dir_entry = readdir(dp); + if(dir_entry == NULL) + break; + + /* On ne prend pas les fichiers invisibles */ + if(dir_entry->d_name[0] == '.') + continue; + /* On ne prend pas les répertoires */ + if(dir_entry->d_type == DT_DIR) + continue; + + /** Garde le fichier **/ + /* Allocation mémoire */ + current_item = (struct item *) calloc(1,sizeof(struct item)); + if(current_item == NULL) + { + closedir(dp); + /* Libération mémoire */ + for(current_item = first_item; current_item; current_item = next_item) + { + next_item = current_item->next; + if(current_item->name) + free(current_item->name); + free(current_item); + } + *is_error = 1; + return(NULL); + } + current_item->name = strdup(dir_entry->d_name); + if(current_item->name == NULL) + { + closedir(dp); + /* Libération mémoire */ + for(current_item = first_item; current_item; current_item = next_item) + { + next_item = current_item->next; + if(current_item->name) + free(current_item->name); + free(current_item); + } + *is_error = 1; + return(NULL); + } + /* Ajout dans la liste */ + nb_item++; + if(first_item == NULL) + first_item = current_item; + else + last_item->next = current_item; + last_item = current_item; + } + + /* Fermeture du répertoire */ + closedir(dp); +#endif + + /* Rien trouvé ? */ + if(nb_item == 0) + { + *nb_file_rtn = 0; + return(NULL); + } + + /** Conversion Liste -> Table **/ + tab_file_name = (char **) calloc(nb_item,sizeof(char *)); + if(tab_file_name == NULL) + { + /* Libération mémoire */ + for(current_item = first_item; current_item; current_item = next_item) + { + next_item = current_item->next; + if(current_item->name) + free(current_item->name); + free(current_item); + } + *is_error = 1; + return(NULL); + } + + /* Ajout des noms */ + for(current_item = first_item; current_item; current_item = current_item->next) + tab_file_name[nb_file++] = current_item->name; + + /* Libération de la liste (mais pas du name) */ + for(current_item = first_item; current_item; current_item = next_item) + { + next_item = current_item->next; + free(current_item); + } + + /* Renvoi la liste */ + *nb_file_rtn = nb_file; + return(tab_file_name); +} + + +/*****************************************************************/ +/* my_IsFileExist() : Détermine si le fichier exite sur disque. */ +/*****************************************************************/ +int my_IsFileExist(char *file_path) +{ + FILE *fd; + int i; + char *file_case_path = NULL; + char file_path_windows[1024] = ""; + char file_path_unix[1024] = ""; + + /** Les noms ne sont pas case-sensitives sous Windows **/ +#if defined(WIN32) || defined(WIN64) + /* Chemin Windows */ + strcpy(file_path_windows,file_path); + for(i=0; i<(int)strlen(file_path_windows); i++) + if(file_path_windows[i] == '/') + file_path_windows[i] = '\\'; + + /* Ouverture du fichier */ + fd = fopen(file_path_windows,"r"); + if(fd == NULL) + return(0); /* N'existe pas */ + + /* Fermeture */ + fclose(fd); + + /* Existe */ + return(1); +#else + /** Les noms sont case-sensitives sous Unix **/ + /* Chemin Unix */ + strcpy(file_path_unix,file_path); + for(i=0; i<(int)strlen(file_path_unix); i++) + if(file_path_unix[i] == '\\') + file_path_unix[i] = '/'; + + /* Ouverture du fichier */ + fd = fopen(file_path_unix,"r"); + if(fd != NULL) + { + /* Existe */ + fclose(fd); + return(1); + } + + /** Recherche le nom exact du fichier dans le répertoire **/ + file_case_path = GetFileProperCasePath(file_path); + if(file_case_path != NULL) + return(1); /* Trouvé */ + + /* Pas trouvé */ + return(0); +#endif +} + + +/*********************************************************************/ +/* LoadTextFileData() : Récupération des données d'un fichier Txt. */ +/*********************************************************************/ +unsigned char *LoadTextFileData(char *file_path, int *data_length_rtn) +{ + FILE *fd; + int nb_read, file_size; + unsigned char *data; + char *file_case_path = NULL; + char file_path_unix[1024] = ""; + + /** Ouverture du fichier **/ + fd = fopen(file_path,"r"); + if(fd == NULL) + { +#if defined(WIN32) || defined(WIN64) + return(NULL); +#else + /** Les noms sont case-sensitive sous Unix **/ + /* Quick Win => On remplace le .s par .S */ + if(strlen(file_path) > 2) + if(file_path[strlen(file_path)-2] == '.' && toupper(file_path[strlen(file_path)-1]) == 'S') + { + /* Change Case of the .s */ + strcpy(file_path_unix,file_path); + if(file_path_unix[strlen(file_path_unix)-1] == 'S') + file_path_unix[strlen(file_path_unix)-1] = 's'; + else + file_path_unix[strlen(file_path_unix)-1] = 'S'; + + /* Re-open file */ + fd = fopen(file_path_unix,"r"); + } + + /* Recherche le nom exact du fichier dans le répertoire */ + if(fd == NULL) + { + file_case_path = GetFileProperCasePath(file_path); + if(file_case_path != NULL) + fd = fopen(file_case_path,"r"); + } + + /* Rien trouvé */ + if(fd == NULL) + return(NULL); +#endif + } + + /* Taille du fichier */ + fseek(fd,0L,SEEK_END); + file_size = ftell(fd); + fseek(fd,0L,SEEK_SET); + + /* Allocation mémoire */ + data = (unsigned char *) calloc(1,file_size+1); + if(data == NULL) + { + fclose(fd); + return(NULL); + } + + /* Lecture des données */ + nb_read = (int) fread(data,1,file_size,fd); + if(nb_read < 0) + { + free(data); + fclose(fd); + return(NULL); + } + data[nb_read] = '\0'; + + /* Fermeture du fichier */ + fclose(fd); + + /* Renvoi les données et la taille */ + *data_length_rtn = nb_read; + return(data); +} + + +/***********************************************************************/ +/* LoadBinaryFileData() : Récupération des données d'un fichier Bin. */ +/***********************************************************************/ +unsigned char *LoadBinaryFileData(char *file_path, int *data_length_rtn) +{ + FILE *fd; + int nb_read, file_size; + unsigned char *data; + char *file_case_path = NULL; + + /* Ouverture du fichier */ +#if defined(WIN32) || defined(WIN64) + fd = fopen(file_path,"rb"); +#else + /** Les noms sont case-sensitive sous Unix **/ + fd = fopen(file_path,"r"); + if(fd == NULL) + { + /* Recherche le nom exact du fichier dans le répertoire */ + file_case_path = GetFileProperCasePath(file_path); + if(file_case_path != NULL) + fd = fopen(file_case_path,"r"); + } +#endif + if(fd == NULL) + return(NULL); + + /* Taille du fichier */ + fseek(fd,0L,SEEK_END); + file_size = ftell(fd); + fseek(fd,0L,SEEK_SET); + + /* Allocation mémoire */ + data = (unsigned char *) calloc(1,file_size+1); + if(data == NULL) + { + fclose(fd); + return(NULL); + } + + /* Lecture des données */ + nb_read = (int) fread(data,1,file_size,fd); + if(nb_read < 0) + { + free(data); + fclose(fd); + return(NULL); + } + + /* Fermeture du fichier */ + fclose(fd); + + /* Renvoi les données et la taille */ + *data_length_rtn = nb_read; + return(data); +} + + +/*****************************************************************/ +/* GetLabelFromLine() : Isole une des composantes de la ligne. */ +/*****************************************************************/ +int GetLabelFromLine(char *data, int offset, char *value_rtn) +{ + int i, length; + + /* Init */ + strcpy(value_rtn,""); + + /* A t'on qqchose ? */ + if(data[offset] == ' ' || data[offset] == '\n') + { + /* Vide, on va donc rechercher le prochain caractère */ + for(length=0; length<(int)strlen(data); length++) + if(data[offset+length] != ' ' && data[offset+length] != '\t') + break; + } + else + { + /* Recopie la valeur */ + for(i=0; data[i+offset] != ' ' && data[i+offset] != '\t' && data[i+offset] != '\0'; i++) + value_rtn[i] = data[i+offset]; + value_rtn[i] = '\0'; + + /* Elimine la zone vide qui suit */ + for(length=i; length<(int)strlen(data); length++) + if(data[offset+length] != ' ' && data[offset+length] != '\t') + break; + } + + /* Renvoie le nouvel offset */ + return(offset+length); +} + + +/******************************************************************/ +/* GetOpcodeFromLine() : Isole une des composantes de la ligne. */ +/******************************************************************/ +int GetOpcodeFromLine(char *data, int offset, char *value_rtn) +{ + int i; + + /* Init */ + strcpy(value_rtn,""); + + /* Rien */ + if(strlen(&data[offset]) == 0) + return(offset); + + /* Recopie la valeur */ + for(i=0; data[i+offset] != ' ' && data[i+offset] != '\t' && data[i+offset] != '\0'; i++) + value_rtn[i] = data[i+offset]; + value_rtn[i] = '\0'; + + /* Renvoie le nouvel offset */ + return(offset+i); +} + + +/*****************************************************/ +/* CleanBuffer() : On nettoy un buffer genre @Trim */ +/*****************************************************/ +void CleanBuffer(char *buffer) +{ + int i, j; + int length; + + /* Nettoyage arrière */ + length = (int) strlen(buffer); + for(i=length-1; i>=0; i--) + if(buffer[i] == '\0' || buffer[i] == ' ' || buffer[i] == '\n' || buffer[i] == '\t') + buffer[i] = '\0'; + else + break; + + /* Nettoyage avant */ + length = (int) strlen(buffer); + for(i=0,j=0; i 0) + memmove(&buffer[0],&buffer[j],(length-j)+1); +} + + +/*****************************************************/ +/* CleanUpName() : Enlève les ' ou " autour du nom */ +/*****************************************************/ +void CleanUpName(char *buffer) +{ + size_t length; + + /* Longueur */ + length = strlen(buffer); + if(length < 2) + return; + + /* Y a t'il des ' ou des " autour du nom */ + if((buffer[0] == '\'' && buffer[length-1] == '\'') || (buffer[0] == '"' && buffer[length-1] == '"')) + { + memmove(&buffer[0],&buffer[1],length-2); + buffer[length-2] = '\0'; + } +} + + +/**************************************************************/ +/* GetFolderFromPath() : Extrait le répertoire d'un chemin. */ +/**************************************************************/ +void GetFolderFromPath(char *file_path, char *folder_path_rtn) +{ + int i; + + /* Init */ + strcpy(folder_path_rtn,""); + + /* On extrait le chemin */ + for(i=(int)strlen(file_path); i>=0; i--) + if(file_path[i] == '\\' || file_path[i] == '/') + { + memcpy(folder_path_rtn,file_path,i+1); + folder_path_rtn[i+1] = '\0'; + break; + } +} + + +/*******************************************************************/ +/* ExtractAllIem() : Sépare les différents éléments d'une ligne. */ +/*******************************************************************/ +struct item *ExtractAllIem(char *data) +{ + int i, j, end, length, offset; + struct item *current_item; + struct item *first_item = NULL; + struct item *last_item = NULL; + int value_type; + char value[1024]; + + /* Cas particulier : Ligne vide */ + length = (int) strlen(data); + if(length == 0) + return(NULL); + + /* Cas particulier : Ligne commentaire */ + if(data[0] == '*' || data[0] == ';') + { + current_item = mem_alloc_item(data,TYPE_DATA); + return(current_item); + } + + /** Parcours la ligne **/ + value[0] = '\0'; + for(i=0,offset=0; inext = current_item; + last_item = current_item; + + /* Début d'une nouvelle valeur SEPARATOR */ + offset = 0; + value[offset++] = data[i]; + value_type = TYPE_SEPARATOR; + } + } + else + { + if(offset == 0) /* 1ère valeur */ + { + /* Cas particulier : une valeur DATA commencant par un ; est un commentaire qui va jusqu'à la fin de la ligne */ + if(data[i] == ';') + { + current_item = mem_alloc_item(&data[i],TYPE_DATA); + if(first_item == NULL) + first_item = current_item; + else + last_item->next = current_item; + last_item = current_item; + return(first_item); + } + + /* Cas particulier pour " et ' : On va jusqu'à la fin */ + if(data[i] == '"' || data[i] == '\'') + { + /* Y a t'il une fin de chaine ? */ + for(j=i+1,end=0; jnext = current_item; + last_item = current_item; + + /* Nouvelle DATA */ + offset = 0; + value_type = TYPE_DATA; + + /** Début d'une nouvelle valeur DATA **/ + /* Cas particulier : une valeur DATA commencant par un ; est un commentaire qui va jusqu'à la fin de la ligne */ + if(data[i] == ';') + { + current_item = mem_alloc_item(&data[i],TYPE_DATA); + if(first_item == NULL) + first_item = current_item; + else + last_item->next = current_item; + last_item = current_item; + return(first_item); + } + + /* Cas particulier pour " et ' : On va jusqu'à la fin */ + if(data[i] == '"' || data[i] == '\'') + { + /* Y a t'il une fin de chaine ? */ + for(j=i+1,end=0; j 0) + { + value[offset] = '\0'; + current_item = mem_alloc_item(value,value_type); + if(first_item == NULL) + first_item = current_item; + else + last_item->next = current_item; + last_item = current_item; + } + + /* Renvoie la liste chainée */ + return(first_item); +} + + +/************************************************/ +/* IsDecimal() : Est-ce une valeur Décimale ? */ +/************************************************/ +int IsDecimal(char *value, int *nb_byte_rtn) +{ + int i, decimal, is_negative; + + /* Init */ + *nb_byte_rtn = 0; + is_negative = 0; + + /* Valeur vide */ + if(strlen(value) == 0) + return(0); + + /* On peut avoir un -3 */ + if(value[0] == '-') + is_negative = 1; + + /* On teste la plage de caractère 0-9 */ + for(i=is_negative; i<(int)strlen(value); i++) + if(value[i] < '0' || value[i] > '9') + return(0); + + /* Détermine le nombre d'octets */ + decimal = atoi(value); + if(decimal <= 0xFF) + *nb_byte_rtn = 1; + else if(decimal <= 0xFFFF) + *nb_byte_rtn = 2; + else if(decimal <= 0xFFFFFF) + *nb_byte_rtn = 3; + else + return(0); /* Valeur trop grande */ + + /* OK */ + return(1); +} + + +/*******************************************************/ +/* IsHexaDecimal() : Est-ce une valeur hexadécimal ? */ +/*******************************************************/ +int IsHexaDecimal(char *value, int *nb_byte_rtn) +{ + int i, is_negative, length; + char hexa_value[16]; + + /* Init */ + *nb_byte_rtn = 0; + is_negative = 0; + + /* Le premier caractère doit être un $ */ + if(value[0] != '$') + return(0); + + /* Valeur vide */ + if(strlen(value) == 1) + return(0); + + /* On peut avoir un $-3, attention ici 3 est en décimal ! */ + if(value[1] == '-') + is_negative = 1; + + /* On teste la plage de caractère 0-F */ + for(i=1+is_negative; i<(int)strlen(value); i++) + if(toupper(value[i]) < '0' || toupper(value[i]) > 'F') + return(0); + + /* Détermine le nombre d'octets (4 octets max pour le LONG) */ + if(is_negative == 1) + { + /* On convertit en Hexa */ + sprintf(hexa_value,"%X",atoi(&value[2])); + length = (int) strlen(hexa_value); + if((length%2) == 1) + length++; + if((length/2) > 4) + return(0); /* Valeur trop grande */ + *nb_byte_rtn = length/2; + } + else + { + /* Valeur vraiment codée en Hexa */ + length = (int) strlen(&value[1]); + if((length%2) == 1) + length++; + if((length / 2) > 4) + return(0); /* Valeur trop grande */ + *nb_byte_rtn = length/2; + } + + /* OK */ + return(1); +} + + +/*************************************************/ +/* IsBinary() : Est-ce une expression binaire ? */ +/*************************************************/ +int IsBinary(char *value, int *nb_byte_rtn) +{ + int i, nb_bit; + + /* Init */ + *nb_byte_rtn = 0; + + /* Le premier caractère est un % */ + if(value[0] != '%') + return(0); + + /* Vérifie la plage de valeur */ + for(i=1,nb_bit=0; i<(int)strlen(value); i++) + { + if(value[i] == '0' || value[i] == '1') + nb_bit++; + else if(value[i] == '_') + ; /* Séparateur */ + else + return(0); /* Valeur Interdite */ + } + + /* Valeur vide */ + if(nb_bit == 0) + return(0); + + /* Détermine le nombre d'octet */ + if(nb_bit <= 8) + *nb_byte_rtn = 1; + else if(nb_bit <= 16) + *nb_byte_rtn = 2; + else if(nb_bit <= 24) + *nb_byte_rtn = 3; + else + return(0); /* Trop de valeur */ + + /* OK */ + return(1); +} + + +/*******************************************************/ +/* IsAscii() : Est-ce une expression Ascii "" ou '' ? */ +/*******************************************************/ +int IsAscii(char *value, int *nb_byte_rtn) +{ + int i, nb_char; + + /* Init */ + *nb_byte_rtn = 0; + + /* Vide */ + if(strlen(value) < 2) + return(0); + + /* Le premier caractère est un " ou un ' */ + if(value[0] != '"' && value[0] != '\'') + return(0); + if(value[0] != value[strlen(value)-1]) + return(0); + + /* Compte le nombre de caractères entre les "" */ + for(i=1,nb_char=0; i<(int)strlen(value)-1; i++) + nb_char++; + + /* Valeur vide */ + if(nb_char == 0) + return(0); + + /* Détermine le nombre d'octet */ + if(nb_char == 1) + *nb_byte_rtn = 1; + else if(nb_char == 2) + *nb_byte_rtn = 2; + else + return(0); /* Trop de valeur */ + + /* OK */ + return(1); +} + + +/*****************************************************/ +/* IsVariable() : Est-ce une expression ]Variable. */ +/*****************************************************/ +int IsVariable(char *value, int *nb_byte_rtn, struct omf_segment *current_omfsegment) +{ + struct variable *current_variable; + + /* Init */ + *nb_byte_rtn = 0; + + /* Vide */ + if(strlen(value) < 2) + return(0); + + /* Le premier caractère est un ] */ + if(value[0] != ']') + return(0); + + /* Récupère la variable */ + my_Memory(MEMORY_SEARCH_VARIABLE,value,¤t_variable,current_omfsegment); + if(current_variable == NULL) + return(0); + + /* On essaye d'évaluer la valeur de la Variable */ + + /* Nombre d'octets de la valeur */ + if(current_variable->value < 256) + *nb_byte_rtn = 1; + else if(current_variable->value < 65536) + *nb_byte_rtn = 2; + else + *nb_byte_rtn = 3; + + /* OK */ + return(1); +} + + +/***********************************/ +/* IsLabel() : Est-ce un Label ? */ +/***********************************/ +int IsLabel(char *name, int *nb_byte_rtn, struct omf_segment *current_omfsegment) +{ + struct label *current_label; + + /* Init */ + *nb_byte_rtn = 0; + + /** Recherche un Label avec ce nom **/ + my_Memory(MEMORY_SEARCH_LABEL,name,¤t_label,current_omfsegment); + if(current_label != NULL) + { + *nb_byte_rtn = 2; + return(1); + } + + /* Pas trouvé */ + return(0); +} + + +/*****************************************/ +/* IsExternal() : Est-ce un External ? */ +/*****************************************/ +int IsExternal(char *name, int *nb_byte_rtn, struct omf_segment *current_omfsegment) +{ + struct external *current_external; + + /* Init */ + *nb_byte_rtn = 0; + + /** Recherche un External avec ce nom **/ + my_Memory(MEMORY_SEARCH_EXTERNAL,name,¤t_external,current_omfsegment); + if(current_external != NULL) + { + *nb_byte_rtn = 3; + return(1); + } + + /* Pas trouvé */ + return(0); +} + + +/*********************************************/ +/* GetUNID() : Création d'un label unique. */ +/*********************************************/ +void GetUNID(char *unique_rtn) +{ + int new_index; + static int index = 1; + + /* Init ? */ + if(!my_strnicmp(unique_rtn,"INIT=",strlen("INIT="))) + { + new_index = atoi(&unique_rtn[strlen("INIT=")]); + if(new_index > index) + index = new_index; + } + else + sprintf(unique_rtn,"ozunid_%d",index++); +} + + +/*******************************************************************/ +/* ProcessOZUNIDLine() : Attention, le source a déjà du ozunid_. */ +/*******************************************************************/ +void ProcessOZUNIDLine(char *label) +{ + int i, index; + char buffer[256]; + + /* Cas particulier */ + if(strlen(label) <= strlen("ozunid_")) + return; + + /* On va extraire le chiffre */ + for(i=(int)strlen("ozunid_"); i<(int)strlen(label); i++) + if(label[i] < '0' || label[i] > '9') + return; + + /* On a bien un chiffre, on passe donc au suivant */ + index = atoi(label) + 1; + + /* Initialise le compteur */ + sprintf(buffer,"INIT=%d",index); + GetUNID(buffer); +} + + +/*****************************************************************************/ +/* ReplaceInOperand() : Remplace dans l'Operand des chaines de caractères. */ +/*****************************************************************************/ +char *ReplaceInOperand(char *string, char *search_string, char *replace_string, int separator_mode, struct source_line *current_line) +{ + int i, nb_found; + int nb_element; + char **tab_element; + char *new_string = NULL; + + /* Cas particuliers : current_line peut être NULL si on remplace dans une Macro */ + if(strlen(string) == 0 || strlen(search_string) == 0 || strlen(string) < strlen(search_string)) + return(string); + + /*** Recherche la présence de la chaine search_string dans string ***/ + /** Recherche rapide (case sensitive) **/ + for(i=0,nb_found=0; i<(int)(strlen(string) - strlen(search_string) + 1); i++) + if(!strncmp(&string[i],search_string,strlen(search_string))) + { + nb_found++; + i += (int) strlen(search_string)-1; + } + + /* Rien trouvé */ + if(nb_found == 0) + return(string); + + /** Allocation mémoire (on prévoit plus large) **/ + new_string = (char *) calloc(strlen(string)+nb_found*strlen(replace_string)+1,sizeof(char)); + if(new_string == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for 'new_string'"); + + /** On va découper l'opérande en plusieurs éléments unitaires **/ + tab_element = DecodeOperandeAsElementTable(string,&nb_element,separator_mode,current_line); + if(tab_element == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to decode operand as element table"); + + /** On reconstruit la chaine en remplacant les valeurs (case sensitive) **/ + for(i=0; i' || string[i] == '\\' || string[i] == '!' || + string[i] == '|' || string[i] == '@' || string[i] == '{' || string[i] == '}' || + string[i] == '=' || string[i] == '\t' || string[i] == '\n') + nb_element += 2; + + /* Allocation mémoire du tableau */ + tab_element = (char **) calloc(nb_element,sizeof(char *)); + if(tab_element == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for a table"); + + /*** On va placer les éléments dans le tableau ***/ + for(i=0,j=0,nb_element=0; i<(int) strlen(string); i++) + { + /***************************/ + /** Chaines de caractères **/ + /***************************/ + if(string[i] == '"' || string[i] == '\'') + { + /* Termine le précédant */ + if(IsSeparator(string[i],separator_mode)) + { + buffer[j] = '\0'; + tab_element[nb_element] = strdup(buffer); + if(tab_element[nb_element] == NULL) + { + mem_free_table(nb_element,tab_element); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for an item into a table"); + } + nb_element++; + j = 0; + } + + /* On stocke la chaine entourée par ses délimiteurs */ + buffer[j++] = string[i]; + for(k=i+1,found=0; k<(int) strlen(string); k++) + { + buffer[j++] = string[k]; + if(string[k] == string[i]) + { + found = 1; + break; + } + } + + /* Chaine invalide : Pas de fin */ + if(found == 0) + { + if(current_line == NULL) + printf(" Error : Wrong format for '%s' : Missing String delimiter (Macro).\n",string); + else + printf(" Error : Wrong format for '%s' : Missing String delimiter (File '%s', Line %d).\n",string,current_line->file->file_name,current_line->file_line_number); + mem_free_table(nb_element,tab_element); + return(NULL); + } + + /* On stocke la chaine entourée par ses délimiteurs */ + if(IsSeparator(string[i],separator_mode)) + { + buffer[j] = '\0'; + tab_element[nb_element] = strdup(buffer); + if(tab_element[nb_element] == NULL) + { + mem_free_table(nb_element,tab_element); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for an item into a table"); + } + nb_element++; + j = 0; + } + + /* Continue après la chaine */ + i += (k-i+1) - 1; + continue; + } + + /******************************************/ + /** Valeur numérique, Label ou Opérateur **/ + /******************************************/ + if(separator_mode == SEPARATOR_EVALUATE_EXPRESSION) + { + /*** A cause des Opérateurs ambigus, on doit gérér séparément le découpage de l'expression à évaluer ***/ + + /** Cas Simple 1 : Ni Opérateur ni Séparateur **/ + if(!IsSeparator(string[i],SEPARATOR_EVALUATE_EXPRESSION)) + { + /* Ajoute ce caractère au buffer */ + buffer[j++] = string[i]; + continue; + } + + /** Cas Simple 2 : Opérateurs ou Séparateurs non ambigus (* est peut etre l'adresse courante mais on va l'isoler dans un item comme on ferait avec un opérateur) **/ + if(string[i] == '+' || string[i] == '*' || string[i] == '/' || string[i] == '&' || string[i] == '.' || string[i] == '!' || string[i] == '{' || string[i] == '}' || string[i] == ' ' || string[i] == '\t' || string[i] == '\n') + { + /* Termine le précédent */ + buffer[j] = '\0'; + if(j > 0) + { + /* Ajoute l'élément */ + tab_element[nb_element] = strdup(buffer); + if(tab_element[nb_element] == NULL) + { + mem_free_table(nb_element,tab_element); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for an item into a table"); + } + nb_element++; + + /* Ré-Initialise */ + j = 0; + } + + /* Stocke le séparateur seul (sauf si c'est un séparateur neutre : espace, \t, \n) */ + if(string[i] != ' ' && string[i] != '\n' && string[i] != '\t') + { + /* Ajoute l'élément */ + buffer[0] = string[i]; + buffer[1] = '\0'; + tab_element[nb_element] = strdup(buffer); + if(tab_element[nb_element] == NULL) + { + mem_free_table(nb_element,tab_element); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for an item into a table"); + } + nb_element++; + } + + /* Continue */ + continue; + } + + /*** Il faut gérer < > # et - comme des cas particuliers => ce ne sont pas forcément des séparateurs ***/ + + /** Cas particulier : '-' comme opérateur unaire encapsulé (#-1 ou $-3 ou #$-2) **/ + if(string[i] == '-' && j > 0) + if(buffer[j-1] == '#' || buffer[j-1] == '$') + if((string[i+1] >= '0' && string[i+1] <= '9') || (toupper(string[i+1]) >= 'A' && toupper(string[i+1]) <= 'F')) /* On gère le décimal et l'hexa */ + { + /* On inclu le - comme signe de la valeur */ + buffer[j++] = string[i]; + continue; + } + + /** Cas particulier : < > et # utilisé comme mode d'adressage **/ + if(string[i] == '<' || string[i] == '>' || string[i] == '#') + { + /* Cas 1 : Tout au début de l'expression */ + if(j == 0 && nb_element == 0) + { + /* On inclu le <># comme 1ère lettre de la valeur à venir */ + buffer[j++] = string[i]; + continue; + } + + /* Cas 2 : < et > ont un # juste avant (#>LABEL ou #') && j == 1) + if(buffer[0] == '#') + { + /* On inclu le <> comme 2ème lettre de la valeur en cours */ + buffer[j++] = string[i]; + continue; + } + + /* Cas 3 : Un opérateur ou un sépatareur les précède */ + if(j == 0 && nb_element > 0) + { + if(strlen(tab_element[nb_element-1]) == 1 && IsSeparator(tab_element[nb_element-1][0],SEPARATOR_EVALUATE_EXPRESSION)) + { + /* On inclu le <># comme 1ère lettre de la valeur à venir */ + buffer[j++] = string[i]; + continue; + } + } + } + + /** Finalement, il s'agit bien d'Opérateurs => Termine la valeur précédente + Stocke l'opérateur seul **/ + /* Termine le précédent */ + buffer[j] = '\0'; + if(j > 0) + { + /* Ajoute l'élément */ + tab_element[nb_element] = strdup(buffer); + if(tab_element[nb_element] == NULL) + { + mem_free_table(nb_element,tab_element); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for an item into a table"); + } + nb_element++; + + /* Ré-Initialise */ + j = 0; + } + + /* Stocke le séparateur seul (sauf si c'est un séparateur neutre : espace, \t, \n) */ + if(string[i] != ' ' && string[i] != '\n' && string[i] != '\t') + { + /* Ajoute l'élément */ + buffer[0] = string[i]; + buffer[1] = '\0'; + tab_element[nb_element] = strdup(buffer); + if(tab_element[nb_element] == NULL) + { + mem_free_table(nb_element,tab_element); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for an item into a table"); + } + nb_element++; + } + } + else + { + /** On cherche les séparateurs **/ + if(IsSeparator(string[i],separator_mode)) + { + /* Termine le précédent */ + buffer[j] = '\0'; + if(j > 0) + { + tab_element[nb_element] = strdup(buffer); + if(tab_element[nb_element] == NULL) + { + mem_free_table(nb_element,tab_element); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for an item into a table"); + } + nb_element++; + } + + /* Stocke le séparateur seul (sauf si c'est un séparateur neutre : espace, \t, \n) */ + if(string[i] != ' ' && string[i] != '\n' && string[i] != '\t') + { + buffer[0] = string[i]; + buffer[1] = '\0'; + tab_element[nb_element] = strdup(buffer); + if(tab_element[nb_element] == NULL) + { + mem_free_table(nb_element,tab_element); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for an item into a table"); + } + nb_element++; + } + + /* Ré-Initialise */ + j = 0; + + /* Continue */ + continue; + } + + /* Ajoute ce caractère au buffer */ + buffer[j++] = string[i]; + } + } + + /** Dernier élément restant **/ + buffer[j] = '\0'; + if(j > 0) + { + tab_element[nb_element] = strdup(buffer); + if(tab_element[nb_element] == NULL) + { + mem_free_table(nb_element,tab_element); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for an item into a table"); + } + nb_element++; + } + + /* Renvoi le tableau */ + *nb_element_rtn = nb_element; + return(tab_element); +} + + +/******************************************************************/ +/* IsSeparator() : Détermine si le caractère est un séparateur. */ +/******************************************************************/ +int IsSeparator(char c, int separator_mode) +{ + /** Si on analyse pour remplacer les Label, le $ n'est pas considéré comme un séparateur ($BB avec BB comme EQU) **/ + if(separator_mode == SEPARATOR_REPLACE_LABEL) + { + /* Liste des séparateurs */ + if(c == ' ' || c == '+' || c == '-' || c == '.' || c == '&' || c == '!' || c == '*' || c == '/' || + c == '#' || c == ',' || c == ';' || c == '<' || c == '>' || c == '^' || c == '|' || c == '[' || + c == ']' || c == '(' || c == ')' || c == '{' || c == '}' || c == '%' || c == '=') + return(1); + } + /** Si on analyse pour remplacer les Label Variable, le ] et le $ ne sont pas considérés comme un séparateur **/ + else if(separator_mode == SEPARATOR_REPLACE_VARIABLE) + { + /* Liste des séparateurs */ + if(c == ' ' || c == '+' || c == '-' || c == '.' || c == '&' || c == '!' || c == '*' || c == '/' || + c == '#' || c == ',' || c == ';' || c == '<' || c == '>' || c == '^' || c == '|' || c == '[' || + c == '(' || c == ')' || c == '{' || c == '}' || c == '%' || c == '=') + return(1); + } + /** On va devoir évaluer une expression, le découpage se fait selon les opérateurs **/ + else if(separator_mode == SEPARATOR_EVALUATE_EXPRESSION) + { + /* Liste des séparateurs */ + if(c == '<' || c == '=' || c == '>' || c == '#' || /* < egal > different */ + c == '+' || c == '-' || c == '*' || c == '/' || /* + - * / */ + c == '&' || c == '.' || c == '!' || /* ET / OU / EXCLUSIF */ + c == '{' || c == '}' || c == ' ' || c == '\t' || c == '\n') /* Priorité d'Opérateurs / Séparateurs */ + return(1); + } + /** Les data sont séparées par des , **/ + else if(separator_mode == SEPARATOR_DATA_VALUES) + { + /* Liste des séparateurs */ + if(c == ',') + return(1); + } + + /* Pas un séparateur */ + return(0); +} + + +/***********************************************************************/ +/* GetByteValue() : Décode une valeur BYTE codée en Hexa ou Décimal. */ +/***********************************************************************/ +BYTE GetByteValue(char *value_txt) +{ + BYTE value_byte; + int i, j; + unsigned int value_int = 0; + int offset = 0; + int is_hexa = 0; + int is_binary = 0; + + /* A t'on un # en premier ? */ + if(value_txt[offset] == '#') + offset++; + + /* A t'on un $ en suivant */ + if(value_txt[offset] == '$') + { + offset++; + is_hexa = 1; + } + else if(value_txt[offset] == '%') + { + offset++; + is_binary = 1; + } + + /** On décode la valeur **/ + if(is_binary) + { + for(i=0,j=0; i<(int)strlen(&value_txt[offset]); i++) + { + if(value_txt[offset+strlen(&value_txt[offset])-1-i] == '1') + { + value_int += (1 << j); + j++; + } + else if(value_txt[offset+strlen(&value_txt[offset])-1-i] == '0') + j++; + } + } + else if(is_hexa) + sscanf(&value_txt[offset],"%X",&value_int); + else + sscanf(&value_txt[offset],"%d",&value_int); + + /* Conversion en BYTE */ + value_byte = (BYTE) value_int; + + /* Renvoie la valeur */ + return(value_byte); +} + + +/***********************************************************************/ +/* GetWordValue() : Décode une valeur WORD codée en Hexa ou Décimal. */ +/***********************************************************************/ +WORD GetWordValue(char *value_txt) +{ + WORD value_wd; + int i, j; + unsigned int value_int = 0; + int offset = 0; + int is_hexa = 0; + int is_binary = 0; + + /* A t'on un # en premier ? */ + if(value_txt[offset] == '#') + offset++; + + /* A t'on un $ en suivant */ + if(value_txt[offset] == '$') + { + offset++; + is_hexa = 1; + } + else if(value_txt[offset] == '%') + { + offset++; + is_binary = 1; + } + + /** On décode la valeur **/ + if(is_binary) + { + for(i=0,j=0; i<(int)strlen(&value_txt[offset]); i++) + { + if(value_txt[offset+strlen(&value_txt[offset])-1-i] == '1') + { + value_int += (1 << j); + j++; + } + else if(value_txt[offset+strlen(&value_txt[offset])-1-i] == '0') + j++; + } + } + else if(is_hexa) + sscanf(&value_txt[offset],"%X",&value_int); + else + sscanf(&value_txt[offset],"%d",&value_int); + + /* Conversion en WORD */ + value_wd = (WORD) value_int; + + /* Renvoie la valeur */ + return(value_wd); +} + + +/*************************************************************************/ +/* GetDwordValue() : Décode une valeur DWORD codée en Hexa ou Décimal. */ +/*************************************************************************/ +DWORD GetDwordValue(char *value_txt) +{ + DWORD value_dwd; + int i, j; + unsigned int value_int = 0; + int offset = 0; + int is_hexa = 0; + int is_binary = 0; + + /* A t'on un # en premier ? */ + if(value_txt[offset] == '#') + offset++; + + /* A t'on un $ en suivant */ + if(value_txt[offset] == '$') + { + offset++; + is_hexa = 1; + } + else if(value_txt[offset] == '%') + { + offset++; + is_binary = 1; + } + + /** On décode la valeur **/ + if(is_binary) + { + for(i=0,j=0; i<(int)strlen(&value_txt[offset]); i++) + { + if(value_txt[offset+strlen(&value_txt[offset])-1-i] == '1') + { + value_int += (1 << j); + j++; + } + else if(value_txt[offset+strlen(&value_txt[offset])-1-i] == '0') + j++; + } + } + else if(is_hexa) + sscanf(&value_txt[offset],"%X",&value_int); + else + sscanf(&value_txt[offset],"%d",&value_int); + + /* Conversion en DWORD */ + value_dwd = (DWORD) value_int; + + /* Renvoie la valeur */ + return(value_dwd); +} + + +/****************************************************************/ +/* GetVariableValue() : Récupère l'évaluation d'une variable. */ +/****************************************************************/ +int64_t GetVariableValue(char *variable_name, int *is_error_rtn, struct omf_segment *current_omfsegment) +{ + struct variable *current_variable; + + /* Init */ + *is_error_rtn = 0; + + /** On va rechercher la variable **/ + my_Memory(MEMORY_SEARCH_VARIABLE,variable_name,¤t_variable,current_omfsegment); + if(current_variable == NULL) + { + *is_error_rtn = 1; + return(0); + } + + /* Renvoie la valeur */ + return(current_variable->value); +} + + +/************************************************************************/ +/* GetBinaryValue() : Récupère l'évaluation d'une expression binaire. */ +/************************************************************************/ +int64_t GetBinaryValue(char *expression) +{ + int i; + int64_t value, j, v; + + /* Init */ + v = 1; + value = 0; + + /** On ne veut que des 0,1 et _ **/ + for(j=0,i=(int)strlen(expression)-1; i>=0; i--) + if(expression[i] == '0') + { + j++; + } + else if(expression[i] == '1') + { + value += (v << j); + j++; + } + else if(expression[i] == '_') + continue; + else + return(-1); /* Invalid character for binary */ + + /* Renvoie la valeur */ + return(value); +} + + +/**************************************************************************/ +/* GetDecimalValue() : Récupère l'évaluation d'une expression decimale. */ +/**************************************************************************/ +int64_t GetDecimalValue(char *expression, int *is_error_rtn) +{ + int i, is_negative; + int64_t value; + + /* Init */ + *is_error_rtn = 0; + is_negative = 0; + + /* A t'on une signe - devant ? */ + if(expression[0] == '-') + is_negative = 1; + + /** On ne veut que des 0-9 **/ + for(i=is_negative; i<(int)strlen(expression); i++) + if(expression[i] < '0' || expression[i] > '9') + { + *is_error_rtn = 1; + return(0); /* Invalid character for decimal */ + } + + /* Décode l'expression */ + value = my_atoi64(expression); + + /* Renvoie la valeur */ + return(value); +} + + +/***************************************************************************/ +/* GetHexaValue() : Récupère l'évaluation d'une expression hexadecimale. */ +/***************************************************************************/ +int64_t GetHexaValue(char *expression) +{ + int i, is_negative; + int64_t value, v, j; + + /* Init */ + value = 0; + is_negative = 0; + + /* Signe au début, attention dans $-3, 3 est en décimal ! */ + if(expression[0] == '-') + is_negative = 1; + + /** On ne veut que des 0-9 A-F **/ + for(i=is_negative; i<(int)strlen(expression); i++) + if(!((expression[i] >= '0' && expression[i] <= '9') || (toupper(expression[i]) >= 'A' && toupper(expression[i]) <= 'F'))) + return(-1); /* Invalid character for hexadecimal */ + + /** Décode l'expression Hexa **/ + if(is_negative == 1) + value = atoi(&expression[1]); /* dans $-3, 3 est en décimal ! */ + else + { + for(i=(int)strlen(expression)-1,j=0; i>=is_negative; i--,j+=4) + { + /* Decode le caractère 0-F */ + if(expression[i] >= '0' && expression[i] <= '9') + v = (expression[i] - '0'); + else + v = ((toupper(expression[i]) - 'A') + 10); + + /* Ajoute à la valeur */ + value += (v << j); + } + } + + /* Renvoie la valeur */ + if(is_negative == 1) + return(value*(-1)); + else + return(value); +} + + +/*********************************************************************/ +/* GetAsciiValue() : Récupère l'évaluation d'une expression ascii. */ +/*********************************************************************/ +int64_t GetAsciiValue(char *expression) +{ + int64_t value; + char *next_char; + + /** On veut du "c" ou du "cc" **/ + if(strlen(expression) != 3 && strlen(expression) != 4) + return(-1); + if(expression[0] != expression[strlen(expression)-1]) + return(-1); + if(expression[0] != '"' && expression[0] != '\'') + return(-1); + + /* On vérifie que les caractères sont dans la plage ASCII */ + if(strlen(expression) == 3) + next_char = strchr(ASCII_TABLE,expression[1]); + else + { + next_char = strchr(ASCII_TABLE,expression[1]); + if(next_char != NULL) + next_char = strchr(ASCII_TABLE,expression[2]); + } + if(next_char == NULL) + return(-1); + + /** Décode l'expression **/ + if(strlen(expression) == 3) + { + if(expression[0] == '"') + value = (unsigned char) (expression[1] | 0x80); + if(expression[0] == '\'') + value = (unsigned char) (expression[1] & 0x7F); + } + else + { + if(expression[0] == '"') + value = (((WORD)(expression[2] | 0x80)) << 8) | (WORD) (expression[1] | 0x80); + if(expression[0] == '\'') + value = (((WORD)(expression[2] & 0x7F)) << 8) | (WORD) (expression[1] & 0x7F); + } + + /* Renvoie la valeur */ + return(value); +} + + +/**************************************************************/ +/* GetAddressValue() : Récupère l'évaluation d'une adresse. */ +/**************************************************************/ +int64_t GetAddressValue(char *expression, int current_address, struct external **current_external_rtn, int *is_dum_label_rtn, int *is_fix_label_rtn, struct omf_segment *current_omfsegment) +{ + int64_t address; + struct label *current_label = NULL; + struct external *current_external = NULL; + + /* Init */ + *current_external_rtn = NULL; + *is_dum_label_rtn = 0; /* Par défaut, le label n'est pas DUM */ + *is_fix_label_rtn = 0; /* Par défaut, le label n'est pas ORG */ + + /* Cas particulier du * */ + if(!strcmp(expression,"*")) + return(current_address); + + /* Est-ce un Label External */ + my_Memory(MEMORY_SEARCH_EXTERNAL,expression,¤t_external,current_omfsegment); + if(current_external != NULL) + { + *current_external_rtn = current_external; + address = 0; + return(address); + } + + /* On recherche un Label */ + my_Memory(MEMORY_SEARCH_LABEL,expression,¤t_label,current_omfsegment); + if(current_label == NULL) + return(-1); + + /* Ce label est dans une section DUM */ + if(current_label->line->is_dum == 1) + *is_dum_label_rtn = 1; + + /* Ce label est dans une section [ORG $Addr ORG] */ + if(current_label->line->is_fix_address == 1) + *is_fix_label_rtn = 1; + + /* Le label est valide mais l'adresse est actuellement inconnue */ + if(current_label->line->address == -1) + return(-2); + + /* Calcule l'adresse */ + address = (current_label->line->bank << 16) | (0xFFFF & current_label->line->address); + + /* Renvoie la valeur */ + return(address); +} + + +/***********************************************************************************/ +/* QuickConditionEvaluate() : Evaluation rapide d'une expression conditionnelle. */ +/***********************************************************************************/ +int QuickConditionEvaluate(struct source_line *cond_line, int64_t *value_expression_rtn, struct omf_segment *current_omfsegment) +{ + int i, j, is_dum_label, is_fix_label, is_algebric, first_value_is_negative, nb_element, is_error, nb_open, has_priority, is_operator, nb_item; + int64_t value, value_expression, value_variable, value_binary, value_decimal, value_hexa, value_ascii, value_address; + int has_dash, has_less, has_more, has_exp, has_pipe, has_extra_dash; + char operator_c; + char *new_value_txt; + char **tab_element; + char expression[1024]; + char buffer[1024]; + char buffer_error[1024]; + + /** Trois possibilité : 0 (STATUS_DONT), 1 (STATUS_DO) ou ne sait pas (STATUS_UNKNWON) **/ + /* Quick Win */ + if(!my_stricmp(cond_line->operand_txt,"0")) + { + *value_expression_rtn = 0; + return(STATUS_DONT); + } + if(!my_stricmp(cond_line->operand_txt,"1")) + { + *value_expression_rtn = 1; + return(STATUS_DO); + } + + /* Init */ + has_dash = 0; + is_dum_label = 0; + is_fix_label = 0; + is_algebric = 0; + first_value_is_negative = 0; + value_expression = 0; + + /** On va traiter les # < > ^ | du tout début **/ + has_dash = (cond_line->operand_txt[0] == '#') ? 1 : 0; + has_less = (cond_line->operand_txt[has_dash] == '<') ? 1 : 0; + has_more = (cond_line->operand_txt[has_dash] == '>') ? 1 : 0; + has_exp = (cond_line->operand_txt[has_dash] == '^') ? 1 : 0; + has_pipe = (cond_line->operand_txt[has_dash] == '|' || cond_line->operand_txt[has_dash] == '!') ? 1 : 0; + + /** S'il n'y a aucun opérateur (<=>#+-/ *&.^), on supprime les {} **/ + for(i=(has_dash+has_less+has_more+has_exp+has_pipe); i<(int)strlen(cond_line->operand_txt); i++) + if(cond_line->operand_txt[i] == '=' || /* cond_line->operand_txt[i] == '<' || cond_line->operand_txt[i] == '>' || cond_line->operand_txt[i] == '#' || A REFAIRE */ + cond_line->operand_txt[i] == '+' || cond_line->operand_txt[i] == '-' || cond_line->operand_txt[i] == '/' || cond_line->operand_txt[i] == '*' || + cond_line->operand_txt[i] == '.' || cond_line->operand_txt[i] == '&' || cond_line->operand_txt[i] == '^') + { + is_algebric = 1; + break; + } + if(is_algebric == 0) + { + for(i=0,j=0; i<(int)strlen(cond_line->operand_txt); i++) + if(cond_line->operand_txt[i] != '{' && cond_line->operand_txt[i] != '}') + expression[j++] = cond_line->operand_txt[i]; + expression[j] = '\0'; + } + else + strcpy(expression,cond_line->operand_txt); + + /** On va traiter les # < > ^ | **/ + has_dash = (expression[0] == '#') ? 1 : 0; + has_less = (expression[has_dash] == '<') ? 1 : 0; + has_more = (expression[has_dash] == '>') ? 1 : 0; + has_exp = (expression[has_dash] == '^') ? 1 : 0; + has_pipe = (expression[has_dash] == '|' || expression[has_dash] == '!') ? 1 : 0; + + /** Découpe la chaine de caractères en plusieurs éléments (saute les #><^| du début) **/ + tab_element = DecodeOperandeAsElementTable(&expression[has_dash+has_less+has_more+has_exp+has_pipe],&nb_element,SEPARATOR_EVALUATE_EXPRESSION,cond_line); + if(tab_element == NULL) + { + sprintf(buffer_error,"Impossible to decode Operand '%s' as element table",expression); + return(STATUS_UNKNWON); + } + + /* Expression vide */ + if(nb_element == 0 || (nb_element == 1 && strlen(tab_element[0]) == 0)) + { + /* C'est une erreur */ + strcpy(buffer_error,"Empty expression"); + mem_free_table(nb_element,tab_element); + return(STATUS_UNKNWON); + } + + /** Conversion des élements non Separator en valeur numériques **/ + for(i=0; i Passage de la première valeur en négatif **/ + if(!strcmp(tab_element[0],"-") && nb_element > 1) + { + /* La première valeur est négative */ + first_value_is_negative = 1; + + /* On peut supprimer le - */ + free(tab_element[0]); + for(j=1; jaddress,&nb_item); + else + { + /** La conversion numérique a déjà été faite **/ + value = my_atoi64(tab_element[i]); + } + + /** Ajoute cette valeur à l'expression globale **/ + if(i == 0) + value_expression = value*((first_value_is_negative == 1) ? -1 : 1); + else + { + /** Applique l'opérateur aux deux valeurs **/ + if(operator_c == '>') + value_expression = (value_expression > value) ? 1 : 0; + else if(operator_c == '=') + value_expression = (value_expression == value) ? 1 : 0; + else if(operator_c == '<') + value_expression = (value_expression < value) ? 1 : 0; + else if(operator_c == '#') + value_expression = (value_expression != value) ? 1 : 0; + else if(operator_c == '+') + value_expression = value_expression + value; + else if (operator_c == '-') + value_expression = value_expression - value; + else if (operator_c == '*') + value_expression = value_expression * value; + else if (operator_c == '/') + { + /* Attention aux divisions par Zéro */ + if(value == 0) + { + strcpy(buffer_error,"Division by Zero"); + mem_free_table(nb_element,tab_element); + return(STATUS_UNKNWON); + } + + value_expression = value_expression / value; + } + else if (operator_c == '!') + value_expression = value_expression ^ value; + else if (operator_c == '.') + value_expression = value_expression | value; + else if (operator_c == '&') + value_expression = value_expression & value; + } + + /* Le prochain sera un operateur */ + is_operator = 1; + + /* Si on a eu un { on saute toute l'expression */ + if(!strcmp(tab_element[i],"{")) + i += nb_item; + } + else + { + /** On doit reconnaître l'opérateur **/ + if(strcmp(tab_element[i],"<") && strcmp(tab_element[i],"=") && strcmp(tab_element[i],">") && strcmp(tab_element[i],"#") && + strcmp(tab_element[i],"+") && strcmp(tab_element[i],"-") && strcmp(tab_element[i],"*") && strcmp(tab_element[i],"/") && + strcmp(tab_element[i],"!") && strcmp(tab_element[i],".") && strcmp(tab_element[i],"&")) + { + sprintf(buffer_error,"The '%s' is not a valid operator",tab_element[i]); + mem_free_table(nb_element,tab_element); + return(STATUS_UNKNWON); + } + + /* Conserve l'opérateur pour la suite */ + operator_c = tab_element[i][0]; + + /* Le prochain sera une valeur */ + is_operator = 0; + } + } + + /* Libération mémoire */ + mem_free_table(nb_element,tab_element); + + /* On sait trancher */ + *value_expression_rtn = value_expression; + if(value_expression == 0) + return(STATUS_DONT); + else + return(STATUS_DO); +} + + +/**************************************************************/ +/* GetQuickValue() : Récupère la valeur d'un élément nommé. */ +/**************************************************************/ +int64_t GetQuickValue(char *name, struct source_line *cond_line, int *is_error_rtn, struct omf_segment *current_omfsegment) +{ + int i, result, nb_valid_line; + int64_t value_expression; + struct source_line **tab_line; + struct source_line *current_line; + + /** Tableau d'accès rapide aux lignes **/ + /* Nombre de lignes valides */ + for(nb_valid_line=0,current_line = current_omfsegment->first_file->first_line; current_line; current_line=current_line->next) + { + if(current_line == cond_line) + break; + if(current_line->is_valid == 0) + continue; + nb_valid_line++; + } + /* Allocation mémoire */ + tab_line = (struct source_line **) calloc(nb_valid_line+1,sizeof(struct source_line *)); + if(tab_line == NULL) + { + *is_error_rtn = 1; + return(-1); + } + /* Remplissage */ + for(i=0,current_line = current_omfsegment->first_file->first_line; current_line; current_line=current_line->next) + { + if(current_line == cond_line) + break; + if(current_line->is_valid == 0) + continue; + tab_line[i++] = current_line; + } + + /** On va de bas en haut pour les Labels et les Equ **/ + for(i=nb_valid_line-1; i>=0; i--) + if(!strcmp(name,tab_line[i]->label_txt)) + { + /* Equ */ + if(!my_stricmp(tab_line[i]->opcode_txt,"EQU") || !my_stricmp(tab_line[i]->opcode_txt,"=")) + { + /** On va devoir évaluer l'Opérande (récursivité) **/ + result = QuickConditionEvaluate(tab_line[i],&value_expression,current_omfsegment); + if(result == STATUS_UNKNWON) + { + /* Impossible à évaluer */ + free(tab_line); + *is_error_rtn = 1; + return(-1); + } + + /* Libération mémoire */ + free(tab_line); + + /* Renvoi la valeur */ + *is_error_rtn = 0; + return(value_expression); + } + else /* Label Simple */ + { + /* On renvoi l'adresse approximative de la ligne du Label */ + free(tab_line); + *is_error_rtn = 0; + return(2*i); + } + } + + /* Libération mémoire */ + free(tab_line); + + /* On a pas trouvé */ + *is_error_rtn = 1; + return(-1); +} + + +/*************************************************************/ +/* GetQuickVariable() : Récupère la valeur d'une variable. */ +/*************************************************************/ +int64_t GetQuickVariable(char *variable_name, struct source_line *cond_line, int *is_error_rtn, struct omf_segment *current_omfsegment) +{ + int result, is_variable; + int64_t value_expression; + struct source_line *current_line; + + /** Il faut différencier la ]Variable du ]Label local **/ + is_variable = 1; + for(current_line = current_omfsegment->first_file->first_line; current_line; current_line=current_line->next) + { + if(current_line == cond_line) + break; + if(current_line->is_valid == 0) + continue; + + /* ]Label ou ]Variable */ + if(!strcmp(current_line->label_txt,variable_name)) + { + if(!my_stricmp(current_line->opcode_txt,"=")) + is_variable = 1; + else + is_variable = 0; + break; + } + } + + /** C'est un ]Label local **/ + if(is_variable == 0) + { + /* On utilise la fonction d'évaluation d'un Label */ + value_expression = GetQuickValue(variable_name,cond_line,is_error_rtn,current_omfsegment); + return(value_expression); + } + + /** On va de bas en haut pour trouver la valeur de la ]Variable **/ + for(current_line = current_omfsegment->first_file->first_line; current_line; current_line=current_line->next) + { + if(current_line == cond_line) + break; + if(current_line->is_valid == 0) + continue; + + /* Cherche la 1ère définition de la Variable */ + if(!strcmp(variable_name,current_line->label_txt) && !my_stricmp(current_line->opcode_txt,"=")) + { + /** On va devoir évaluer l'Opérande (récursivité) **/ + result = QuickConditionEvaluate(current_line,&value_expression,current_omfsegment); + if(result == STATUS_UNKNWON) + { + /* Impossible à évaluer */ + *is_error_rtn = 1; + return(-1); + } + + /* Renvoi la valeur */ + *is_error_rtn = 0; + return(value_expression); + } + } + + /* On a pas trouvé */ + *is_error_rtn = 1; + return(-1); +} + + +/**************************************************************/ +/* EvalExpressionAsInteger() : Evaluation d'une expression. */ +/**************************************************************/ +int64_t EvalExpressionAsInteger(char *expression_param, char *buffer_error_rtn, struct source_line *current_line, int operand_size, int *is_reloc_rtn, BYTE *byte_count_rtn, BYTE *bit_shift_rtn, WORD *offset_reference_rtn, DWORD *expression_address_rtn, struct external **external_rtn, struct omf_segment *current_omfsegment) +{ + int has_priority, nb_open, is_algebric; + int64_t value, value_expression, value_variable, value_binary, value_decimal, value_hexa, value_ascii, value_address; + char *new_value_txt; + int i, j, nb_element, is_operator, first_value_is_negative, nb_address, has_extra_dash, nb_item, is_pea_opcode, is_mvn_opcode, is_error, is_dum_label, is_fix_label; + int has_dash, has_less, has_more, has_exp, has_pipe; + char expression[1024]; + struct external *current_external; + struct external *has_external; + char **tab_element; + char operator_c; + char dash_char[10] = ""; + char addr_char[10] = ""; + char buffer[1024]; + + /* Init */ + has_dash = 0; + strcpy(buffer_error_rtn,""); + *is_reloc_rtn = 0; + *bit_shift_rtn = 0; /* Aucune manipulation de Bit */ + is_dum_label = 0; + is_fix_label = 0; + nb_address = 0; + is_algebric = 0; + current_external = NULL; + *offset_reference_rtn = 0x0000; + *byte_count_rtn = current_line->nb_byte-1; /* Taille de l'Operand */ + *expression_address_rtn = 0xFFFFFFFF; /* Ce n'est pas une Adresse Longue */ + *external_rtn = NULL; + first_value_is_negative = 0; + is_pea_opcode = !my_stricmp(current_line->opcode_txt,"PEA"); + is_mvn_opcode = (!my_stricmp(current_line->opcode_txt,"MVN") || !my_stricmp(current_line->opcode_txt,"MVP")); + + /** On va traiter les # < > ^ | du tout début **/ + has_dash = (expression_param[0] == '#') ? 1 : 0; + has_less = (expression_param[has_dash] == '<') ? 1 : 0; + has_more = (expression_param[has_dash] == '>') ? 1 : 0; + has_exp = (expression_param[has_dash] == '^') ? 1 : 0; + has_pipe = (expression_param[has_dash] == '|' || expression_param[has_dash] == '!') ? 1 : 0; + + /** S'il n'y a aucun opérateur (<=>#+-/ *&.^), on supprime les {} **/ + for(i=(has_dash+has_less+has_more+has_exp+has_pipe); i<(int)strlen(expression_param); i++) + if(expression_param[i] == '=' || /* expression_param[i] == '<' || expression_param[i] == '>' || expression_param[i] == '#' || A REFAIRE */ + expression_param[i] == '+' || expression_param[i] == '-' || expression_param[i] == '/' || expression_param[i] == '*' || + expression_param[i] == '.' || expression_param[i] == '&' || expression_param[i] == '^') + { + is_algebric = 1; + break; + } + if(is_algebric == 0) + { + for(i=0,j=0; i<(int)strlen(expression_param); i++) + if(expression_param[i] != '{' && expression_param[i] != '}') + expression[j++] = expression_param[i]; + expression[j] = '\0'; + } + else + strcpy(expression,expression_param); + + /** On va traiter les # < > ^ | **/ + has_dash = (expression[0] == '#') ? 1 : 0; + has_less = (expression[has_dash] == '<') ? 1 : 0; + has_more = (expression[has_dash] == '>') ? 1 : 0; + has_exp = (expression[has_dash] == '^') ? 1 : 0; + has_pipe = (expression[has_dash] == '|' || expression[has_dash] == '!') ? 1 : 0; + + /** Découpe la chaine de caractères en plusieurs éléments (saute les #><^| du début) **/ + tab_element = DecodeOperandeAsElementTable(&expression[has_dash+has_less+has_more+has_exp+has_pipe],&nb_element,SEPARATOR_EVALUATE_EXPRESSION,current_line); + if(tab_element == NULL) + { + sprintf(buffer_error_rtn,"Impossible to decode Operand '%s' as element table",expression); + return(0); + } + + /* Expression vide */ + if(nb_element == 0 || (nb_element == 1 && strlen(tab_element[0]) == 0)) + { + /* Cas particulier du BRK/COP/WDM sans signature */ + if(!my_stricmp(current_line->opcode_txt,"BRK") || !my_stricmp(current_line->opcode_txt,"COP") || !my_stricmp(current_line->opcode_txt,"WDM")) + return(0); + + /* C'est une erreur */ + strcpy(buffer_error_rtn,"Empty expression"); + mem_free_table(nb_element,tab_element); + return(0); + } + + /** On va remplacer les MX **/ + if(strcmp(current_line->m,"?") && strcmp(current_line->x,"?")) + { + for(i=0; im) << 1)|atoi(current_line->x)); + new_value_txt = strdup(buffer); + if(new_value_txt == NULL) + { + mem_free_table(nb_element,tab_element); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for new 'value_txt'"); + } + free(tab_element[i]); + tab_element[i] = new_value_txt; + } + } + } + + /** On va évaluer/remplacer les ]Variable **/ + for(i=0; iaddress,&has_external,&is_dum_label,&is_fix_label,current_omfsegment); + if(value_address == -2) + { + /* L'adresse n'est pas prête */ + sprintf(buffer_error_rtn,"Address of label '%s' is unknown at this time",&tab_element[i][has_extra_dash]); + mem_free_table(nb_element,tab_element); + return(0xFFFF); + } + else if(value_address != -1) + { + /* On peut remplacer l'expression */ + my_printf64(value_address,buffer); + new_value_txt = strdup(buffer); + if(new_value_txt == NULL) + { + mem_free_table(nb_element,tab_element); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for new 'value_txt'"); + } + free(tab_element[i]); + tab_element[i] = new_value_txt; + + /* On a détecté une adresse relogeable (les DUM et les FIX ne sont pas relogeable) */ + if(is_dum_label == 0 && is_fix_label == 0) + nb_address++; + + /** Le label est dans un Segment externe **/ + if(has_external != NULL) + { + if(current_external == NULL) + current_external = has_external; + else + { + /* Erreur : L'utilisation de Label externe impose certaines contraintes dans les expressions */ + sprintf(buffer_error_rtn,"You can't use 2 External labels (%s and %s) in the same expression",current_external->name,has_external->name); + mem_free_table(nb_element,tab_element); + return(0); + } + + /* L'expression fait déjà appel à au moins un Label Interne : on ne mélange pas Interne et Externe */ + if(nb_address > 1) + { + /* Erreur : L'utilisation de Label externe impose certaines contraintes dans les expressions */ + sprintf(buffer_error_rtn,"You can't mix an External label (%s) with an Internal label (%s) the same expression",has_external->name,&tab_element[i][has_extra_dash]); + mem_free_table(nb_element,tab_element); + return(0); + } + } + else + { + /** On ne mélange pas External et Internal **/ + if(current_external != NULL) + { + /* Erreur : L'utilisation de Label externe impose certaines contraintes dans les expressions */ + sprintf(buffer_error_rtn,"You can't mix an Internal label (%s) with an External label (%s) the same expression",&tab_element[i][has_extra_dash],current_external->name); + mem_free_table(nb_element,tab_element); + return(0); + } + } + } + else + { + /** On a peut être une constante numérique **/ + value_decimal = GetDecimalValue(&tab_element[i][has_extra_dash],&is_error); + if(is_error == 0) + { + /* On peut remplacer l'expression */ + my_printf64(value_decimal,buffer); + new_value_txt = strdup(buffer); + if(new_value_txt == NULL) + { + mem_free_table(nb_element,tab_element); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for new 'value_txt'"); + } + free(tab_element[i]); + tab_element[i] = new_value_txt; + } + else + { + /** On ne sait pas comment interpretter cette valeur **/ + sprintf(buffer_error_rtn,"'%s' can't be translated as a numeric expression",tab_element[i]); + mem_free_table(nb_element,tab_element); + return(0); + } + } + } + } + + /** On va gérer le - au début => Passage de la première valeur en négatif **/ + if(!strcmp(tab_element[0],"-") && nb_element > 1) + { + /* La première valeur est négative */ + first_value_is_negative = 1; + + /* On peut supprimer le - */ + free(tab_element[0]); + for(j=1; jaddress,&nb_item); + else + { + /** La conversion numérique a déjà été faite **/ + value = my_atoi64(tab_element[i]); + } + + /** Ajoute cette valeur à l'expression globale **/ + if(i == 0) + value_expression = value*((first_value_is_negative == 1) ? -1 : 1); + else + { + /** Applique l'opérateur aux deux valeurs **/ + if(operator_c == '>') + value_expression = (value_expression > value) ? 1 : 0; + else if(operator_c == '=') + value_expression = (value_expression == value) ? 1 : 0; + else if(operator_c == '<') + value_expression = (value_expression < value) ? 1 : 0; + else if(operator_c == '#') + value_expression = (value_expression != value) ? 1 : 0; + else if(operator_c == '+') + value_expression = value_expression + value; + else if (operator_c == '-') + value_expression = value_expression - value; + else if (operator_c == '*') + value_expression = value_expression * value; + else if (operator_c == '/') + { + /* Attention aux divisions par Zéro */ + if(value == 0) + { + strcpy(buffer_error_rtn,"Division by Zero"); + mem_free_table(nb_element,tab_element); + return(0); + } + + value_expression = value_expression / value; + } + else if (operator_c == '!') + value_expression = value_expression ^ value; + else if (operator_c == '.') + value_expression = value_expression | value; + else if (operator_c == '&') + value_expression = value_expression & value; + } + + /* Le prochain sera un operateur */ + is_operator = 1; + + /* Si on a eu un { on saute toute l'expression */ + if(!strcmp(tab_element[i],"{")) + i += nb_item; + } + else + { + /** On doit reconnaître l'opérateur **/ + if(strcmp(tab_element[i],"<") && strcmp(tab_element[i],"=") && strcmp(tab_element[i],">") && strcmp(tab_element[i],"#") && + strcmp(tab_element[i],"+") && strcmp(tab_element[i],"-") && strcmp(tab_element[i],"*") && strcmp(tab_element[i],"/") && + strcmp(tab_element[i],"!") && strcmp(tab_element[i],".") && strcmp(tab_element[i],"&")) + { + sprintf(buffer_error_rtn,"The '%s' is not a valid operator",tab_element[i]); + mem_free_table(nb_element,tab_element); + return(0); + } + + /* Conserve l'opérateur pour la suite */ + operator_c = tab_element[i][0]; + + /* Le prochain sera une valeur */ + is_operator = 0; + } + } + + /* Libération mémoire */ + mem_free_table(nb_element,tab_element); + + /** On donne les informations de relogeabilité via les Prefix #><^| **/ + if((nb_address%2) == 1) + { + /* On renvoie une adresse relogeable */ + *is_reloc_rtn = 1; + *expression_address_rtn = (0x00FFFFFF & value_expression); /* Adresse Longue 24 bit : Bank/HighLow */ + + /* Ligne de Code */ + if(current_line->type == LINE_CODE) + { + /* Nombre de Byte à reloger */ + if((has_dash == 1 || is_pea_opcode == 1) && has_exp == 1) /* #^ = 1 ou 2 Byte à reloger */ + { + /* Pour un Label Externe, on reloge 2 bytes */ + if(*external_rtn != NULL) + { + if(operand_size == 1) + *byte_count_rtn = 1; + else + *byte_count_rtn = 2; + } + else + *byte_count_rtn = 1; /* Pour un label interne, on reloge 1 byte */ + } + else + *byte_count_rtn = operand_size; + + /* Bit Shift Count */ + if((has_dash == 1 || is_pea_opcode == 1) && has_more == 1) + *bit_shift_rtn = 0xF8; /* >> 8 */ + else if(((has_dash == 1 || is_pea_opcode == 1) && has_exp == 1) || is_mvn_opcode == 1) + *bit_shift_rtn = 0xF0; /* >> 16 */ + else + *bit_shift_rtn = 0x00; + + /* On pointe vers le label External */ + if(current_external != NULL) + *external_rtn = current_external; + } + else if(current_line->type == LINE_DATA) + { + /* Nombre de Byte à reloger */ + if(operand_size == 3 || operand_size == 4) + *byte_count_rtn = 3; + else if(has_exp == 1) /* ^ = 1 Byte à reloger */ + *byte_count_rtn = 1; + else + *byte_count_rtn = operand_size; + + /* Bit Shift Count */ + if(has_more == 1) + *bit_shift_rtn = 0xF8; /* >> 8 */ + else if(has_exp == 1) + *bit_shift_rtn = 0xF0; /* >> 16 */ + else + *bit_shift_rtn = 0x00; + + /* On pointe vers le label External */ + if(current_external != NULL) + *external_rtn = current_external; + } + + /* Offset où est stockée la valeur pointée */ + *offset_reference_rtn = (WORD) value_expression; + } + else + *expression_address_rtn = (0x00FFFFFF & value_expression); /* Adresse Longue 24 bit : Bank/HighLow */ + + /** On modifie la valeur renvoyée en fonction des Prefix #><^| **/ + if((has_dash == 1 || is_pea_opcode == 1 || current_line->type == LINE_DATA) && has_more == 1) + value_expression = value_expression >> 8; + else if((has_dash == 1 || is_pea_opcode == 1 || current_line->type == LINE_DATA) && has_exp == 1) + value_expression = value_expression >> 16; + + /* Renvoie l'expression */ + return(value_expression); +} + + +/****************************************************************************************/ +/* EvaluateAlgebricExpression() : Evaluation d'une expression Algébrique avec des {}. */ +/****************************************************************************************/ +int64_t EvaluateAlgebricExpression(char **tab_element, int current_element, int nb_element, int address, int *nb_item_rtn) +{ + int i, j, nb_open, last_element, is_value, stack_pointer, output_pointer, value_index; + int64_t value; + char address_line[256]; + int64_t value_tab[256]; + char **stack; + char **output; + + /* On prépare l'adresse */ + sprintf(address_line,"%d",address); + + /** On repère les {} **/ + for(i=current_element,nb_open=0; i=0; j--) + { + if(!my_stricmp(stack[j],"{")) + break; + output[output_pointer++] = stack[j]; + stack_pointer--; + } + stack_pointer--; + } + else if(is_value == 1) + { + /* Ajoute cette valeur dans l'output */ + if(!my_stricmp(tab_element[i],"*")) + output[output_pointer++] = &address_line[0]; /* * est l'adresse courrante */ + else + output[output_pointer++] = tab_element[i]; + + /* Le prochain élément sera un opérateur */ + is_value = 0; + } + else + { + /* Ajoute cet Opérateur */ + if(stack_pointer == 0) + stack[stack_pointer++] = tab_element[i]; + else if(!my_stricmp(stack[stack_pointer-1],"{")) + stack[stack_pointer++] = tab_element[i]; + else if(HasPriority(tab_element[i],stack[stack_pointer-1])) + stack[stack_pointer++] = tab_element[i]; + else + { + output[output_pointer++] = stack[stack_pointer-1]; + stack[stack_pointer-1] = tab_element[i]; + } + + /* Le prochain élément sera une valeur */ + is_value = 1; + } + } + /* S'il reste des trucs sur la pile, on dépile */ + for(j=stack_pointer-1; j>=0; j--) + output[output_pointer++] = stack[j]; + + /** On dépile et on évalue **/ + value_index = 0; + for(i=0; i") || !my_stricmp(output[i],"#") || + !my_stricmp(output[i],"+") || !my_stricmp(output[i],"-") || !my_stricmp(output[i],"*") || !my_stricmp(output[i],"/") || + !my_stricmp(output[i],"&") || !my_stricmp(output[i],".") || !my_stricmp(output[i],"!")) + { + if(!my_stricmp(output[i],"<")) + value_tab[value_index-2] = (value_tab[value_index-2] < value_tab[value_index-1]) ? 1 : 0; + else if(!my_stricmp(output[i],"=")) + value_tab[value_index-2] = (value_tab[value_index-2] == value_tab[value_index-1]) ? 1 : 0; + else if(!my_stricmp(output[i],">")) + value_tab[value_index-2] = (value_tab[value_index-2] > value_tab[value_index-1]) ? 1 : 0; + else if(!my_stricmp(output[i],"#")) + value_tab[value_index-2] = (value_tab[value_index-2] != value_tab[value_index-1]) ? 1 : 0; + else if(!my_stricmp(output[i],"+")) + value_tab[value_index-2] = value_tab[value_index-2] + value_tab[value_index-1]; + else if(!my_stricmp(output[i],"-")) + value_tab[value_index-2] = value_tab[value_index-2] - value_tab[value_index-1]; + else if(!my_stricmp(output[i],"*")) + value_tab[value_index-2] = value_tab[value_index-2] * value_tab[value_index-1]; + else if(!my_stricmp(output[i],"/")) + value_tab[value_index-2] = value_tab[value_index-2] / value_tab[value_index-1]; + else if(!my_stricmp(output[i],"&")) + value_tab[value_index-2] = value_tab[value_index-2] & value_tab[value_index-1]; + else if(!my_stricmp(output[i],".")) + value_tab[value_index-2] = value_tab[value_index-2] | value_tab[value_index-1]; + else if(!my_stricmp(output[i],"!")) + value_tab[value_index-2] = value_tab[value_index-2] ^ value_tab[value_index-1]; + value_index--; + } + else + value_tab[value_index++] = my_atoi64(output[i]); + } + value = value_tab[0]; + + /* Libération mémoire */ + free(stack); + free(output); + + /* Nombre d'item */ + *nb_item_rtn = (last_element - current_element); + + /* Renvoi la valeur */ + return(value); +} + + +/*********************************************************/ +/* HasPriority() : Etablit la priorité des opérateurs. */ +/*********************************************************/ +int HasPriority(char *op1, char *op2) +{ + int p1, p2; + + /* Priorité de l'Opérateur 1 */ + if(!my_stricmp(op1,"<") || !my_stricmp(op1,"=") || !my_stricmp(op1,">") || !my_stricmp(op1,"#")) + p1 = 0; + else if(!my_stricmp(op1,"+") || !my_stricmp(op1,"-")) + p1 = 1; + else if(!my_stricmp(op1,"*") || !my_stricmp(op1,"/")) + p1 = 2; + else if(!my_stricmp(op1,"&") || !my_stricmp(op1,".") || !my_stricmp(op1,"!")) + p1 = 3; + + /* Priorité de l'Opérateur 2 */ + if(!my_stricmp(op2,"<") || !my_stricmp(op2,"=") || !my_stricmp(op2,">") || !my_stricmp(op2,"#")) + p2 = 0; + else if(!my_stricmp(op2,"+") || !my_stricmp(op2,"-")) + p2 = 1; + else if(!my_stricmp(op2,"*") || !my_stricmp(op2,"/")) + p2 = 2; + else if(!my_stricmp(op2,"&") || !my_stricmp(op2,".") || !my_stricmp(op2,"!")) + p2 = 3; + + /* Comparaison */ + return((p1>p2)?1:0); +} + + +/*************************************************************************/ +/* BuildBestMVXWord() : Renvoie les octets d'operand pour les MVN/MVP. */ +/*************************************************************************/ +int BuildBestMVXWord(DWORD value_1, DWORD value_2) +{ + BYTE byte_high, byte_low; + BYTE value_byte_1[4]; + BYTE value_byte_2[4]; + + /* Transforme les valeurs en octets (en respectant le Byte Order) */ + bo_memcpy(&value_byte_1[0],&value_1,sizeof(DWORD)); + bo_memcpy(&value_byte_2[0],&value_2,sizeof(DWORD)); + + /* On prend les premiers Byte non nuls (en privilégiant les + forts) */ + byte_high = (value_byte_1[2] != 0x00 || value_byte_1[1] != 0x00) ? value_byte_1[2] : value_byte_1[0]; + byte_low = (value_byte_2[2] != 0x00 || value_byte_2[1] != 0x00) ? value_byte_2[2] : value_byte_2[0]; + + /* Valeurs des Banks */ + return((int)(((WORD)byte_high) << 8 | byte_low)); +} + + +/***********************************************************************/ +/* IsPageDirectOpcode() : Est-ce un opcode acceptant la Page Direct. */ +/***********************************************************************/ +int IsPageDirectOpcode(char *opcode) +{ + int i; + char *opcode_list[] = {"ADC","AND","ASL","BIT","CMP","CPX","CPY","DEC","EOR","INC","LDA","LDX","LDY","LSR","ORA","ROL","ROR","SBC","STA","STX","STY","STZ","TRB","TSB",NULL}; + + /* Recherche un Opcode acceptant le Page Direct */ + for(i=0; opcode_list[i]; i++) + if(!my_stricmp(opcode_list[i],opcode)) + return(1); + + /* Pas trouvé */ + return(0); +} + + +/*************************************************************************/ +/* IsPageDirectAddressMode() : Est-ce un mode d'adressage Page Direct. */ +/*************************************************************************/ +int IsPageDirectAddressMode(int address_mode) +{ + /* Recherche un mode d'adressage Page Direct */ + if(address_mode == AM_DIRECT_PAGE || address_mode == AM_DIRECT_PAGE_INDEXED_X || address_mode == AM_DIRECT_PAGE_INDEXED_Y || + address_mode == AM_DIRECT_PAGE_INDIRECT || address_mode == AM_DIRECT_PAGE_INDIRECT_LONG || address_mode == AM_DIRECT_PAGE_INDEXED_X_INDIRECT || + address_mode == AM_DIRECT_PAGE_INDIRECT_INDEXED_Y || address_mode == AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y) + return(1); + + /* Pas trouvé */ + return(0); +} + + +/*********************************************************************/ +/* IsDirectPageLabel() : Ce Label peut t'il est placé dans une PD. */ +/*********************************************************************/ +int IsDirectPageLabel(char *label_name, struct omf_segment *current_omfsegment) +{ + int64_t dum_address; + int is_reloc; + BYTE byte_count, bit_shift; + WORD offset_reference; + DWORD address_long; + struct label *current_label; + struct source_file *first_file; + struct external *current_external; + char buffer_error[1024] = ""; + + /* Fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /* On recherche le Label */ + my_Memory(MEMORY_SEARCH_LABEL,label_name,¤t_label,current_omfsegment); + if(current_label == NULL) + return(0); + + /* Est ce_un label situé dans un DUM */ + if(current_label->line->is_dum == 1) + { + /* On essaye d'évaluer l'adresse du DUM */ + dum_address = EvalExpressionAsInteger(current_label->line->dum_line->operand_txt,&buffer_error[0],current_label->line->dum_line,2,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) == 0 && dum_address < 0x100) + return(1); /* Peut être */ + else + return(0); /* Non */ + } + else if(current_omfsegment->is_relative == 1) + return(0); + + /* Le ORG le plus proche est t'il < 0x100 */ + + + /* Peut être */ + return(1); +} + + +/**********************************************************************/ +/* UseCurrentAddress() : Y a t'il un * placé en position de valeur. */ +/**********************************************************************/ +int UseCurrentAddress(char *operand, char *buffer_error_rtn, struct source_line *current_line) +{ + int i, nb_element, is_value; + char **tab_element; + + /* Init */ + strcpy(buffer_error_rtn,""); + + /* Recherche rapide */ + if(strchr(operand,'*') == NULL) + return(0); + + /** Découpe la chaine de caractères en plusieurs éléments (saute les #><^| du début) **/ + tab_element = DecodeOperandeAsElementTable(operand,&nb_element,SEPARATOR_EVALUATE_EXPRESSION,current_line); + if(tab_element == NULL) + { + sprintf(buffer_error_rtn,"Impossible to decode Operand '%s' as element table",operand); + return(0); + } + + /** Passe en revue tous les éléments **/ + is_value = 1; + for(i=0; i<^| du début) **/ + tab_element = DecodeOperandeAsElementTable(operand,&nb_element,SEPARATOR_EVALUATE_EXPRESSION,current_line); + if(tab_element == NULL) + { + sprintf(buffer_error_rtn,"Impossible to decode Operand '%s' as element table",operand); + return; + } + + /** Passe en revue tous les éléments **/ + is_value = 1; + for(i=0; i 0) + { + /* Termine la valeur */ + buffer_value[value_length] = '\0'; + + /* Vérifie qu'elle n'existe pas déjà */ + for(j=0; j 0) + { + tab[nb_found] = strdup(buffer_value); + if(tab[nb_found] == NULL) + { + for(j=0; j 0) + { + /* Termine la valeur */ + buffer_value[value_length] = '\0'; + + /* Vérifie qu'elle n'existe pas déjà */ + for(j=0; j 0) + { + tab[nb_found] = strdup(buffer_value); + if(tab[nb_found] == NULL) + { + for(j=0; j 15) + return(0); + + /* Des Lettres, des chiffre ou . */ + for(i=0; i<(int)strlen(file_name); i++) + if(!((file_name[0] >= 'a' && file_name[0] <= 'z') || (file_name[0] >= 'A' && file_name[0] <= 'Z') || + (file_name[0] >= '0' && file_name[0] <= '9') || + file_name[0] == '.')) + return(0); + + /* Une lettre au début */ + if(!((file_name[0] >= 'a' && file_name[0] <= 'z') || (file_name[0] >= 'A' && file_name[0] <= 'Z'))) + return(0); + + /* OK */ + return(1); +} + + +/***********************************************************************/ +/* BuildAbsolutePath() : Construction d'un chemin de fichier absolu. */ +/***********************************************************************/ +void BuildAbsolutePath(char *file_name, char *folder_path, char *file_path_rtn) +{ + /* Init */ + strcpy(file_path_rtn,file_name); + + /* Est ce que le file_name est absolu ? */ + if(file_name[1] == ':' || file_name[0] == '/') + return; + + /* Folder Path + File Name */ + strcpy(file_path_rtn,folder_path); + if(file_name[0] == '/' || file_name[0] == '\\') + strcat(file_path_rtn,&file_name[1]); + else + strcat(file_path_rtn,file_name); +} + + +/********************************************************/ +/* mem_free_list() : Libération mémoire d'un tableau. */ +/********************************************************/ +void mem_free_list(int nb_element, char **element_tab) +{ + int i; + + if(element_tab) + { + for(i=0; iname,item_2->name)); +} + + +/******************************************************************/ +/* compare_macro() : Fonction de comparaison pour le Quick Sort. */ +/******************************************************************/ +int compare_macro(const void *data_1, const void *data_2) +{ + struct macro *macro_1; + struct macro *macro_2; + + /* Récupération des paramètres */ + macro_1 = *((struct macro **) data_1); + macro_2 = *((struct macro **) data_2); + + /* Comparaison des noms des macros (case sensitive) */ + return(strcmp(macro_1->name,macro_2->name)); +} + + +/******************************************************************/ +/* compare_label() : Fonction de comparaison pour le Quick Sort. */ +/******************************************************************/ +int compare_label(const void *data_1, const void *data_2) +{ + struct label *label_1; + struct label *label_2; + + /* Récupération des paramètres */ + label_1 = *((struct label **) data_1); + label_2 = *((struct label **) data_2); + + /* Comparaison des clés : Les labels sont case-sensitifs */ + return(strcmp(label_1->name,label_2->name)); +} + + +/************************************************************************/ +/* compare_equivalence() : Fonction de comparaison pour le Quick Sort. */ +/************************************************************************/ +int compare_equivalence(const void *data_1, const void *data_2) +{ + struct equivalence *equivalence_1; + struct equivalence *equivalence_2; + + /* Récupération des paramètres (case sensitive) */ + equivalence_1 = *((struct equivalence **) data_1); + equivalence_2 = *((struct equivalence **) data_2); + + /* Comparaison des clés */ + return(strcmp(equivalence_1->name,equivalence_2->name)); +} + + +/*********************************************************************/ +/* compare_variable() : Fonction de comparaison pour le Quick Sort. */ +/*********************************************************************/ +int compare_variable(const void *data_1, const void *data_2) +{ + struct variable *variable_1; + struct variable *variable_2; + + /* Récupération des paramètres */ + variable_1 = *((struct variable **) data_1); + variable_2 = *((struct variable **) data_2); + + /* Comparaison des clés (case sensitive) */ + return(strcmp(variable_1->name,variable_2->name)); +} + + +/*********************************************************************/ +/* compare_external() : Fonction de comparaison pour le Quick Sort. */ +/*********************************************************************/ +int compare_external(const void *data_1, const void *data_2) +{ + struct external *external_1; + struct external *external_2; + + /* Récupération des paramètres (case sensitive) */ + external_1 = *((struct external **) data_1); + external_2 = *((struct external **) data_2); + + /* Comparaison des clés */ + return(strcmp(external_1->name,external_2->name)); +} + + +/*****************************************************************/ +/* mem_alloc_item() : Allocation mémoire de la structure item. */ +/*****************************************************************/ +struct item *mem_alloc_item(char *name, int type) +{ + struct item *current_item; + + /* Allocation */ + current_item = (struct item *) calloc(1,sizeof(struct item)); + if(current_item == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for structure item"); + + /* Remplissage */ + current_item->name = strdup(name); + if(current_item->name == NULL) + { + free(current_item); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for 'name' from structure item"); + } + current_item->type = type; + + /* Renvoie la structure */ + return(current_item); +} + + +/****************************************************************/ +/* mem_free_item() : Libération mémoire de la structure item. */ +/****************************************************************/ +void mem_free_item(struct item *current_item) +{ + if(current_item) + { + if(current_item->name) + free(current_item->name); + + free(current_item); + } +} + + +/********************************************************************/ +/* mem_free_item_list() : Libération mémoire des structures item. */ +/********************************************************************/ +void mem_free_item_list(struct item *all_item) +{ + struct item *current_item; + struct item *next_item; + + for(current_item=all_item; current_item; ) + { + next_item = current_item->next; + mem_free_item(current_item); + current_item = next_item; + } +} + + +/*******************************************************************/ +/* mem_alloc_param() : Allocation mémoire de la structure Param. */ +/*******************************************************************/ +struct parameter *mem_alloc_param(void) +{ + WORD one_word; + unsigned char one_word_bin[16]; + time_t clock; + struct tm *p; + int year, hour; + char *month[] = {"JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"}; + struct parameter *param; + + /* Allocation mémoire */ + param = (struct parameter *) calloc(1,sizeof(struct parameter)); + if(param == NULL) + return(NULL); + + /* Buffers (64 KB) */ + param->buffer_line = (char *) calloc(1,65536); + param->buffer_value = (char *) calloc(1,65536); + param->buffer_folder_path = (char *) calloc(1,65536); + param->buffer_file_path = (char *) calloc(1,65536); + param->buffer_file_name = (char *) calloc(1,65536); + param->buffer_label = (char *) calloc(1,65536); + param->buffer_opcode = (char *) calloc(1,65536); + param->buffer_operand = (char *) calloc(1,65536); + param->buffer_comment = (char *) calloc(1,65536); + param->buffer_error = (char *) calloc(1,65536); + param->buffer = (unsigned char *) calloc(1,65536); + + /* Vérification mémoire */ + if(param->buffer_line == NULL || param->buffer_value == NULL || + param->buffer_folder_path == NULL || param->buffer_file_path == NULL || + param->buffer_label == NULL || param->buffer_opcode == NULL || + param->buffer_operand == NULL || param->buffer_comment == NULL || + param->buffer == NULL || param->buffer_file_name == NULL || + param->buffer_error == NULL) + { + mem_free_param(param); + return(NULL); + } + + /* Construit les dates */ + time(&clock); + p = localtime(&clock); + year = (p->tm_year+1900) - 2000; + hour = (p->tm_hour > 12) ? (p->tm_hour - 12) : p->tm_hour; + sprintf(param->date_1,"%02d-%s-%02d",p->tm_mday,month[p->tm_mon],year); + sprintf(param->date_2,"%02d/%02d/%02d",p->tm_mon+1,p->tm_mday,year); + sprintf(param->date_3,"%02d-%s-%02d %2d:%02d:%02d %s",p->tm_mday,month[p->tm_mon],year,hour,p->tm_min,p->tm_sec,(p->tm_hour>12)?"PM":"AM"); + sprintf(param->date_4,"%02d/%02d/%02d %2d:%02d:%02d %s",p->tm_mon+1,p->tm_mday,year,hour,p->tm_min,p->tm_sec,(p->tm_hour>12)?"PM":"AM"); + + /** Byte Order : Little Endian / Big Endian **/ + one_word = 1; + memcpy(&one_word_bin[0],&one_word,sizeof(WORD)); + if(one_word_bin[0] == 0x01) + param->byte_order = BYTE_ORDER_INTEL; /* Little Indian */ + else + param->byte_order = BYTE_ORDER_MOTOROLA; /* Big Endian */ + + /* Renvoie la strcuture */ + return(param); +} + + +/******************************************************************/ +/* mem_free_param() : Libération mémoire de la structure Param. */ +/******************************************************************/ +void mem_free_param(struct parameter *param) +{ + if(param) + { + if(param->buffer_line) + free(param->buffer_line); + + if(param->buffer_value) + free(param->buffer_value); + + if(param->buffer_folder_path) + free(param->buffer_folder_path); + + if(param->buffer_file_path) + free(param->buffer_file_path); + + if(param->buffer_file_name) + free(param->buffer_file_name); + + if(param->buffer_label) + free(param->buffer_label); + + if(param->buffer_opcode) + free(param->buffer_opcode); + + if(param->buffer_operand) + free(param->buffer_operand); + + if(param->buffer_comment) + free(param->buffer_comment); + + if(param->buffer_error) + free(param->buffer_error); + + if(param->buffer) + free(param->buffer); + + free(param); + } +} + + +/************************************************************************/ +/* mem_free_table() : Libération d'une table de chaine de caractères. */ +/************************************************************************/ +void mem_free_table(int nb_item, char **table) +{ + int i; + + if(table == NULL) + return; + + for(i=0; i(b) ? (b) : (a)) + +#define IS_DOLLAR 1 /* $ */ +#define IS_DASH 2 /* # */ +#define IS_POURCENT 3 /* % */ + +#define IS_VALUE 1 +#define IS_CONSTANT 2 /* ( ) [ ] $ # % ,X ,Y ,S + - */ +#define IS_NUMERIC 3 /* 0123456789ABCDEF */ +#define IS_EXPANDABLE 4 /* la valeur doit être éclatée */ + +#define TYPE_DATA 1 +#define TYPE_SEPARATOR 2 + +#define SEPARATOR_REPLACE_LABEL 0 /* Remplace un Label dans une Operande (tous les sépatareurs possibles) */ +#define SEPARATOR_REPLACE_VARIABLE 1 /* Remplace une ]Variable dans une Opérande (tous les séparateurs sauf le ]) */ +#define SEPARATOR_EVALUATE_EXPRESSION 2 /* Prépare l'évaluation d'une expression (on découpe selon les opérateurs : + - / * & . ! < = > #) et on gère les opérateurs ambigus (#><*) ou unaire (-) */ +#define SEPARATOR_DATA_VALUES 3 /* Sépare les différentes valeurs d'une ligne Data (juste le ,) */ + +#define ASCII_TABLE "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?`abcdefghijklmnopqrstuvwxyz{|}~" /* Valide pour ASC, STR... */ +#define INVFLS_TABLE "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?" /* Valide pour INV et FLS */ + +#define SET_FILE_VISIBLE 1 +#define SET_FILE_HIDDEN 2 + +#define STATUS_DONT 0 /* Evaluation d'une condition */ +#define STATUS_DO 1 +#define STATUS_UNKNWON 2 + +struct item +{ + char *name; + int type; + + struct item *next; +}; + +/* Pre-Déclaration des structures */ +struct omf_project; +struct omf_segment; +struct source_line; +struct external; + +void my_RaiseError(int,void *); +void my_Memory(int,void *,void *,struct omf_segment *); +void my_File(int,void *); +int my_stricmp(char *,char *); +int my_strnicmp(char *,char *,size_t); +void my_printf64(int64_t,char *); +int64_t my_atoi64(char *); +int my_IsFileExist(char *); +void bo_memcpy(void *,void *,size_t); +char *GetFileProperCasePath(char *); +char **GetFolderFileList(char *,int *,int *); +unsigned char *LoadTextFileData(char *,int *); +unsigned char *LoadBinaryFileData(char *,int *); +int GetLabelFromLine(char *,int,char *); +int GetOpcodeFromLine(char *,int,char *); +void CleanBuffer(char *); +void CleanUpName(char *); +void GetFolderFromPath(char *,char *); +int IsDecimal(char *,int *); +int IsHexaDecimal(char *,int *); +int IsBinary(char *,int *); +int IsAscii(char *,int *); +int IsVariable(char *,int *,struct omf_segment *); +int IsLabel(char *,int *,struct omf_segment *); +int IsExternal(char *,int *,struct omf_segment *); +void GetUNID(char *); +void ProcessOZUNIDLine(char *); +char *ReplaceInOperand(char *,char *,char *,int,struct source_line *); +char **DecodeOperandeAsElementTable(char *,int *,int,struct source_line *); +struct item *ExtractAllIem(char *); +int IsSeparator(char,int); +BYTE GetByteValue(char *); +WORD GetWordValue(char *); +DWORD GetDwordValue(char *); +int64_t GetVariableValue(char *,int *,struct omf_segment *); +int64_t GetBinaryValue(char *); +int64_t GetDecimalValue(char *,int *); +int64_t GetHexaValue(char *); +int64_t GetAsciiValue(char *); +int64_t GetAddressValue(char *,int,struct external **,int *,int *,struct omf_segment *); +int QuickConditionEvaluate(struct source_line *,int64_t *,struct omf_segment *); +int64_t GetQuickValue(char *,struct source_line *,int *,struct omf_segment *); +int64_t GetQuickVariable(char *,struct source_line *,int *,struct omf_segment *); +int64_t EvalExpressionAsInteger(char *,char *,struct source_line *,int,int *,BYTE *,BYTE *,WORD *,DWORD *,struct external **,struct omf_segment *); +int64_t EvaluateAlgebricExpression(char **,int,int,int,int *); +int HasPriority(char *,char *); +int BuildBestMVXWord(DWORD,DWORD); +int IsPageDirectOpcode(char *); +int IsPageDirectAddressMode(int); +int IsDirectPageLabel(char *,struct omf_segment *); +int UseCurrentAddress(char *,char *,struct source_line *); +void ReplaceCurrentAddressInOperand(char **,char *,char *,struct source_line *); +void my_SetFileAttribute(char *,int); +int CreateBinaryFile(char *,unsigned char *,int); +void my_DeleteFile(char *); +char **BuildUniqueListFromFile(char *,int *); +char **BuildUniqueListFromText(char *,char,int *); +int IsProdosName(char *); +void BuildAbsolutePath(char *,char *,char *); +void mem_free_list(int,char **); +struct parameter *mem_alloc_param(void); +struct item *mem_alloc_item(char *,int); +void mem_free_param(struct parameter *); +void mem_free_item(struct item *); +void mem_free_item_list(struct item *); +void mem_free_table(int, char**); + +/***********************************************************************/ diff --git a/Source/Main.c b/Source/Main.c new file mode 100644 index 0000000..583546d --- /dev/null +++ b/Source/Main.c @@ -0,0 +1,154 @@ +/***********************************************************************/ +/* */ +/* Main.c : Module Assembleur d'un code source 65c816. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +#include +#include +#include +#include +#include + +#include "Dc_Library.h" +#include "a65816_Link.h" +#include "a65816_Line.h" +#include "a65816_File.h" +#include "a65816_Lup.h" +#include "a65816_Macro.h" +#include "a65816_Cond.h" +#include "a65816_Code.h" +#include "a65816_Data.h" +#include "a65816_OMF.h" + +int Assemble65c816(char *,char *,int); + +/****************************************************/ +/* main() : Fonction principale de l'application. */ +/****************************************************/ +int main(int argc, char *argv[]) +{ + jmp_buf context; + int i, verbose_mode, context_value, error; + char *error_string = NULL; + struct omf_segment *current_omfsegment; + struct parameter *param; + char file_error_path[2048]; + char source_file_path[2048]; + char macro_folder_path[2048]; + + /* Message Information */ + printf("%s v 1.0, (c) Brutal Deluxe 2011-2015\n",argv[0]); + + /* Vérification des paramètres */ + if(argc != 3 && argc != 4) + { + printf(" Usage : %s [-V] .\n",argv[0]); + return(1); + } + if(argc == 3 && !my_stricmp(argv[1],"-V")) + { + printf(" Usage : %s [-V] .\n",argv[0]); + return(1); + } + if(argc == 4 && my_stricmp(argv[1],"-V")) + { + printf(" Usage : %s [-V] .\n",argv[0]); + return(1); + } + + /* Décodage des paramètres */ + if(argc == 3) + { + verbose_mode = 0; + strcpy(macro_folder_path,argv[1]); + strcpy(source_file_path,argv[2]); + } + else + { + verbose_mode = 1; + strcpy(macro_folder_path,argv[2]); + strcpy(source_file_path,argv[3]); + } + + /* Initialisation */ + my_Memory(MEMORY_INIT,NULL,NULL,NULL); + my_File(FILE_INIT,NULL); + + /* Initialisation du mécanisme de gestion d'erreurs */ + my_RaiseError(ERROR_INIT,NULL); + context_value = setjmp(context); + if(context_value) + { + /* Récupération de la chaine contenant le message d'erreur */ + my_RaiseError(ERROR_GET_STRING,&error_string); + + /* Message d'erreur et fin */ + if(error_string) + { + printf(" => [Error] %s.\n",error_string); + free(error_string); + } + + /* On récupère le OMF Segment courant (s'il existe) */ + my_Memory(MEMORY_GET_OMFSEGMENT,¤t_omfsegment,NULL,NULL); + + /** On essaye de Dumper qqchose dans le fichier Error_Output.txt **/ + if(current_omfsegment != NULL) + { + strcpy(file_error_path,"error_output.txt"); + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + if(param != NULL) + if(strlen(param->current_folder_path) > 0) + sprintf(file_error_path,"%serror_output.txt",param->current_folder_path); + CreateOutputFile(file_error_path,current_omfsegment,NULL); + } + + /* Libération des ressources */ + my_Memory(MEMORY_FREE,NULL,NULL,NULL); + + /* Error */ + return(1); + } + my_RaiseError(ERROR_INIT,&context); + + /* Allocation mémoire de la structure param */ + param = mem_alloc_param(); + if(param == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for structure parameter"); + my_Memory(MEMORY_SET_PARAM,param,NULL,NULL); + + /** Préparation du dossier Macro **/ + if(strlen(macro_folder_path) > 0) + if(macro_folder_path[strlen(macro_folder_path)-1] != '\\' && macro_folder_path[strlen(macro_folder_path)-1] != '/') + strcat(macro_folder_path,FOLDER_SEPARATOR); + + /** Prépare le chemin des fichiers Output **/ + strcpy(param->output_file_path,source_file_path); + for(i=(int)strlen(param->output_file_path); i>=0; i--) + if(param->output_file_path[i] == '\\' || param->output_file_path[i] == '/') + { + param->output_file_path[i+1] = '\0'; + break; + } + if(i < 0) + strcpy(param->output_file_path,""); + strcpy(param->current_folder_path,param->output_file_path); + + /*** Assemble et Link tous les fichiers du projet ***/ + error = AssembleLink65c816(source_file_path,macro_folder_path,verbose_mode); + + /* Libération des ressources */ + my_File(FILE_FREE,NULL); + my_Memory(MEMORY_FREE,NULL,NULL,NULL); + + /* Fin de la gestion des erreurs */ + my_RaiseError(ERROR_END,NULL); + + /* OK */ + return(0); +} + +/***********************************************************************/ \ No newline at end of file diff --git a/Source/Merlin32 b/Source/Merlin32 new file mode 100755 index 0000000000000000000000000000000000000000..5fe8492a629342a998e7373630971fe3e662ac0f GIT binary patch literal 238168 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

a;k_`iNW`qSh8 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%0AZ44S{qp_`ci88&2&vc0N>n@?)Pl)uh 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 +#include +#include +#include +#include + +#include "Dc_Library.h" +#include "a65816_Line.h" +#include "a65816_File.h" +#include "a65816_Macro.h" +#include "a65816_OMF.h" +#include "a65816_Code.h" + +static void BuildOneCodeLineOpcode(struct source_line *,struct omf_segment *); +static void BuildOneCodeLineOperand(struct source_line *,int *,struct omf_segment *,struct omf_project *); +static void EvaluateOperandAddressMode(char *); +static int DecodeAddressMode(struct source_line *,char *,struct omf_segment *); +static int GetOperandNbByte(char *,struct source_line *,int *,char *,struct omf_segment *); +static int GetBitMode(struct source_line *); + +/**********************************************************************************/ +/* BuildAllCodeLineOpcode() : Calcul de l'Opcode + Taille pour les lignes Code. */ +/**********************************************************************************/ +int BuildAllCodeLineSize(struct omf_segment *current_omfsegment) +{ + struct source_file *first_file; + struct source_line *current_line; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Récupère le 1er fichier source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + if(first_file == NULL) + return(0); + + /*** Passe en revue toutes les lignes pour calculer leur taille ***/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* Cette ligne n'est pas valide */ + if(current_line->is_valid == 0) + { + current_line->nb_byte = 0; + continue; + } + + /** Lignes de Code **/ + if(current_line->type == LINE_CODE) + { + /** Détermine l'Opcode Byte, le mode d'adressage et la taille de Operand **/ + BuildOneCodeLineOpcode(current_line,current_omfsegment); + } + else if(current_line->type == LINE_DATA) + ; /* On ne fait rien pour l'instant */ + else + current_line->nb_byte = 0; + } + + /* OK */ + return(0); +} + + +/**********************************************************************************/ +/* BuildAllCodeLineOpcode() : Calcul de l'Opcode + Taille pour les lignes Code. */ +/**********************************************************************************/ +int BuildAllCodeLine(int *has_error_rtn, struct omf_segment *current_omfsegment, struct omf_project *current_omfproject) +{ + int has_output_name; + struct source_file *first_file; + struct source_line *current_line; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + has_output_name = 0; + + /* Récupère le 1er fichier source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + if(first_file == NULL) + return(0); + + /*** Passe en revue toutes les lignes pour créer le code binaire de l'Operand ***/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* Cette ligne n'est pas valide */ + if(current_line->is_valid == 0 || current_line->is_dum == 1) + continue; + + /** Lignes de Code **/ + if(current_line->type == LINE_CODE) + { + /** Création du code objet de l'Operand **/ + BuildOneCodeLineOperand(current_line,has_error_rtn,current_omfsegment,current_omfproject); + } + else if(current_line->type == LINE_VARIABLE) + { + /** Evaluation de la variable **/ + EvaluateVariableLine(current_line,current_omfsegment); + } + else if(current_line->type == LINE_DIRECTIVE && (!my_stricmp(current_line->opcode_txt,"dsk") || !my_stricmp(current_line->opcode_txt,"lnk") || !my_stricmp(current_line->opcode_txt,"sav"))) + { + /** Conserve le 1er nom qu'on trouve (si le nom du segment n'a pas été apporté par le fichier Link) **/ + if(has_output_name == 0) + { + /* Nom du fichier Objet */ + strcpy(current_omfsegment->object_name,current_line->operand_txt); + + /* Supprime le .L final */ + if(strlen(current_omfsegment->object_name) > 2) + if(!my_stricmp(¤t_omfsegment->object_name[strlen(current_omfsegment->object_name)-2],".L")) + current_omfsegment->object_name[strlen(current_omfsegment->object_name)-2] = '\0'; + + /* On ne prend que le 1er */ + has_output_name = 1; + } + } + } + + /* OK */ + return(0); +} + + +/*****************************************************************************/ +/* BuildOneCodeLineOpcode() : Création de l'Opcode pour une ligne de Code. */ +/*****************************************************************************/ +static void BuildOneCodeLineOpcode(struct source_line *current_line, struct omf_segment *current_omfsegment) +{ + int address_mode; + char buffer_error[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + strcpy(buffer_error,""); + + /** ERR ne produit aucun code mais devra être interpretté **/ + if(!my_stricmp(current_line->opcode_txt,"ERR")) + { + current_line->nb_byte = 0; + current_line->opcode_byte = 0x00; + current_line->address_mode = AM_IMMEDIATE_16; + return; + } + + /** Décodage du mode d'adressage **/ + address_mode = DecodeAddressMode(current_line,&buffer_error[0],current_omfsegment); + if(address_mode == AM_UNKOWN) + { + sprintf(param->buffer_error,"Impossible to decode address mode for instruction '%s %s' (line %d, file '%s')%s%s", + current_line->opcode_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name, + (strlen(buffer_error) > 0) ? " : ":"",buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /** On va traiter tous les Opcodes **/ + if(!my_stricmp(current_line->opcode_txt,"ADC") || !my_stricmp(current_line->opcode_txt,"ADCL")) + { + if(address_mode == AM_IMMEDIATE_8) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x69; + current_line->address_mode = AM_IMMEDIATE_8; + } + else if(address_mode == AM_IMMEDIATE_16) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x69; + current_line->address_mode = AM_IMMEDIATE_16; + } + else if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x6D; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_ABSOLUTE_LONG) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0x6F; + current_line->address_mode = AM_ABSOLUTE_LONG; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x65; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x72; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x67; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x7D; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_LONG_INDEXED_X) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0x7F; + current_line->address_mode = AM_ABSOLUTE_LONG_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_Y || address_mode == AM_DIRECT_PAGE_INDEXED_Y) /* $08,Y doit aussi pouvoir être interpretté comme $0008,Y car DP,Y n'existe pas */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x79; + current_line->address_mode = AM_ABSOLUTE_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x75; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X_INDIRECT) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x61; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x71; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x77; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y; + } + else if(address_mode == AM_STACK_RELATIVE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x63; + current_line->address_mode = AM_STACK_RELATIVE; + } + else if(address_mode == AM_STACK_RELATIVE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x73; + current_line->address_mode = AM_STACK_RELATIVE_INDIRECT_INDEXED_Y; + } + } + else if(!my_stricmp(current_line->opcode_txt,"AND") || !my_stricmp(current_line->opcode_txt,"ANDL")) + { + if(address_mode == AM_IMMEDIATE_8) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x29; + current_line->address_mode = AM_IMMEDIATE_8; + } + else if(address_mode == AM_IMMEDIATE_16) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x29; + current_line->address_mode = AM_IMMEDIATE_16; + } + else if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x2D; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_ABSOLUTE_LONG) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0x2F; + current_line->address_mode = AM_ABSOLUTE_LONG; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x25; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x32; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x27; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x3D; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_LONG_INDEXED_X) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0x3F; + current_line->address_mode = AM_ABSOLUTE_LONG_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_Y || address_mode == AM_DIRECT_PAGE_INDEXED_Y) /* $08,Y doit aussi pouvoir être interpretté comme $0008,Y car DP,Y n'existe pas */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x39; + current_line->address_mode = AM_ABSOLUTE_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x35; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X_INDIRECT) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x21; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x31; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x37; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y; + } + else if(address_mode == AM_STACK_RELATIVE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x23; + current_line->address_mode = AM_STACK_RELATIVE; + } + else if(address_mode == AM_STACK_RELATIVE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x33; + current_line->address_mode = AM_STACK_RELATIVE_INDIRECT_INDEXED_Y; + } + } + else if(!my_stricmp(current_line->opcode_txt,"ASL")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x0A; + current_line->address_mode = AM_IMPLICIT; + } + else if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x0E; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x06; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x1E; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x16; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + } + else if(!my_stricmp(current_line->opcode_txt,"BCC") || !my_stricmp(current_line->opcode_txt,"BLT")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x90; + current_line->address_mode = AM_PC_RELATIVE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"BCS") || !my_stricmp(current_line->opcode_txt,"BGE")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xB0; + current_line->address_mode = AM_PC_RELATIVE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"BEQ")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xF0; + current_line->address_mode = AM_PC_RELATIVE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"BIT")) + { + if(address_mode == AM_IMMEDIATE_8) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x89; + current_line->address_mode = AM_IMMEDIATE_8; + } + else if(address_mode == AM_IMMEDIATE_16) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x89; + current_line->address_mode = AM_IMMEDIATE_16; + } + else if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x2C; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x24; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x3C; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x34; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + } + else if(!my_stricmp(current_line->opcode_txt,"BMI")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x30; + current_line->address_mode = AM_PC_RELATIVE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"BNE")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xD0; + current_line->address_mode = AM_PC_RELATIVE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"BPL")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x10; + current_line->address_mode = AM_PC_RELATIVE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"BRA")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x80; + current_line->address_mode = AM_PC_RELATIVE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"BRK")) + { + if(address_mode == AM_IMPLICIT) /* Le BRK existe avec ou sans octet de signature */ + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x00; + current_line->address_mode = AM_IMPLICIT; + } + else if(address_mode == AM_IMMEDIATE_8 || address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x00; + current_line->address_mode = AM_IMMEDIATE_8; + } + } + else if(!my_stricmp(current_line->opcode_txt,"BRL")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x82; + current_line->address_mode = AM_PC_RELATIVE_LONG; + } + } + else if(!my_stricmp(current_line->opcode_txt,"BVC")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x50; + current_line->address_mode = AM_PC_RELATIVE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"BVS")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x70; + current_line->address_mode = AM_PC_RELATIVE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"CLC")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x18; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"CLD")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xD8; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"CLI")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x58; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"CLV")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xB8; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"CMP") || !my_stricmp(current_line->opcode_txt,"CMPL")) + { + if(address_mode == AM_IMMEDIATE_8) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xC9; + current_line->address_mode = AM_IMMEDIATE_8; + } + else if(address_mode == AM_IMMEDIATE_16) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xC9; + current_line->address_mode = AM_IMMEDIATE_16; + } + else if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xCD; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_ABSOLUTE_LONG) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0xCF; + current_line->address_mode = AM_ABSOLUTE_LONG; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xC5; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xD2; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xC7; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xDD; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_LONG_INDEXED_X) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0xDF; + current_line->address_mode = AM_ABSOLUTE_LONG_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_Y || address_mode == AM_DIRECT_PAGE_INDEXED_Y) /* $08,Y doit aussi pouvoir être interpretté comme $0008,Y car DP,Y n'existe pas */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xD9; + current_line->address_mode = AM_ABSOLUTE_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xD5; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X_INDIRECT) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xC1; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xD1; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xD7; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y; + } + else if(address_mode == AM_STACK_RELATIVE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xC3; + current_line->address_mode = AM_STACK_RELATIVE; + } + else if(address_mode == AM_STACK_RELATIVE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xD3; + current_line->address_mode = AM_STACK_RELATIVE_INDIRECT_INDEXED_Y; + } + } + else if(!my_stricmp(current_line->opcode_txt,"COP")) + { + if(address_mode == AM_IMPLICIT) /* Le COP existe avec ou sans octet de signature */ + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x02; + current_line->address_mode = AM_IMPLICIT; + } + else if(address_mode == AM_IMMEDIATE_8 || address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x02; + current_line->address_mode = AM_IMMEDIATE_8; + } + } + else if(!my_stricmp(current_line->opcode_txt,"CPX")) + { + if(address_mode == AM_IMMEDIATE_8) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xE0; + current_line->address_mode = AM_IMMEDIATE_8; + } + else if(address_mode == AM_IMMEDIATE_16) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xE0; + current_line->address_mode = AM_IMMEDIATE_16; + } + else if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xEC; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xE4; + current_line->address_mode = AM_DIRECT_PAGE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"CPY")) + { + if(address_mode == AM_IMMEDIATE_8) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xC0; + current_line->address_mode = AM_IMMEDIATE_8; + } + else if(address_mode == AM_IMMEDIATE_16) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xC0; + current_line->address_mode = AM_IMMEDIATE_16; + } + else if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xCC; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xC4; + current_line->address_mode = AM_DIRECT_PAGE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"DEC")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x3A; + current_line->address_mode = AM_IMPLICIT; + } + else if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xCE; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xC6; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xDE; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xD6; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + } + else if(!my_stricmp(current_line->opcode_txt,"DEX")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xCA; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"DEY")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x88; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"EOR") || !my_stricmp(current_line->opcode_txt,"EORL")) + { + if(address_mode == AM_IMMEDIATE_8) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x49; + current_line->address_mode = AM_IMMEDIATE_8; + } + else if(address_mode == AM_IMMEDIATE_16) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x49; + current_line->address_mode = AM_IMMEDIATE_16; + } + else if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x4D; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_ABSOLUTE_LONG) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0x4F; + current_line->address_mode = AM_ABSOLUTE_LONG; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x45; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x52; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x47; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x5D; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_LONG_INDEXED_X) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0x5F; + current_line->address_mode = AM_ABSOLUTE_LONG_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_Y || address_mode == AM_DIRECT_PAGE_INDEXED_Y) /* $08,Y doit aussi pouvoir être interpretté comme $0008,Y car DP,Y n'existe pas */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x59; + current_line->address_mode = AM_ABSOLUTE_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x55; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X_INDIRECT) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x41; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x51; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x57; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y; + } + else if(address_mode == AM_STACK_RELATIVE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x43; + current_line->address_mode = AM_STACK_RELATIVE; + } + else if(address_mode == AM_STACK_RELATIVE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x53; + current_line->address_mode = AM_STACK_RELATIVE_INDIRECT_INDEXED_Y; + } + } + else if(!my_stricmp(current_line->opcode_txt,"INC")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x1A; + current_line->address_mode = AM_IMPLICIT; + } + else if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xEE; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xE6; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xFE; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xF6; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + } + else if(!my_stricmp(current_line->opcode_txt,"INX")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xE8; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"INY")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xC8; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"JMP") || !my_stricmp(current_line->opcode_txt,"JML") || !my_stricmp(current_line->opcode_txt,"JMPL")) + { + if(address_mode == AM_ABSOLUTE || address_mode == AM_DIRECT_PAGE) /* On fait passer le $00 pour un $0000 */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x4C; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_ABSOLUTE_INDIRECT || address_mode == AM_DIRECT_PAGE_INDIRECT) /* On fait passer le ($00) pour un ($0000) */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x6C; + current_line->address_mode = AM_ABSOLUTE_INDIRECT; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X_INDIRECT) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x7C; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X_INDIRECT; + } + else if(address_mode == AM_ABSOLUTE_LONG) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0x5C; + current_line->address_mode = AM_ABSOLUTE_LONG; + } + else if(address_mode == AM_ABSOLUTE_INDIRECT_LONG) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xDC; + current_line->address_mode = AM_ABSOLUTE_INDIRECT_LONG; + } + } + else if(!my_stricmp(current_line->opcode_txt,"JSL")) + { + if(address_mode == AM_DIRECT_PAGE || address_mode == AM_ABSOLUTE || address_mode == AM_ABSOLUTE_LONG) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0x22; + current_line->address_mode = AM_ABSOLUTE_LONG; + } + } + else if(!my_stricmp(current_line->opcode_txt,"JSR")) + { + if(address_mode == AM_ABSOLUTE || address_mode == AM_DIRECT_PAGE) /* On fait passer le $00 pour un $0000 */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x20; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X_INDIRECT || address_mode == AM_DIRECT_PAGE_INDEXED_X_INDIRECT) /* On fait passer le ($00,X) pour un ($0000,X) */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xFC; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X_INDIRECT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"LDA") || !my_stricmp(current_line->opcode_txt,"LDAL")) + { + if(address_mode == AM_IMMEDIATE_8) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xA9; + current_line->address_mode = AM_IMMEDIATE_8; + } + else if(address_mode == AM_IMMEDIATE_16) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xA9; + current_line->address_mode = AM_IMMEDIATE_16; + } + else if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xAD; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_ABSOLUTE_LONG) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0xAF; + current_line->address_mode = AM_ABSOLUTE_LONG; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xA5; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT || address_mode == AM_ABSOLUTE_INDIRECT) /* le LDA ($0000) doit être interpretté comme un LDA ($00) */ + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xB2; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG || address_mode == AM_ABSOLUTE_INDIRECT_LONG) /* le LDA [$0000] doit être interpretté comme un LDA [$00] */ + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xA7; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xBD; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_LONG_INDEXED_X) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0xBF; + current_line->address_mode = AM_ABSOLUTE_LONG_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_Y || address_mode == AM_DIRECT_PAGE_INDEXED_Y) /* on avait un LDA $00,Y or le LDA DP,Y n'existe pas, donc ça devait être LDA $0000,Y */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xB9; + current_line->address_mode = AM_ABSOLUTE_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xB5; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X_INDIRECT) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xA1; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xB1; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xB7; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y; + } + else if(address_mode == AM_STACK_RELATIVE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xA3; + current_line->address_mode = AM_STACK_RELATIVE; + } + else if(address_mode == AM_STACK_RELATIVE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xB3; + current_line->address_mode = AM_STACK_RELATIVE_INDIRECT_INDEXED_Y; + } + } + else if(!my_stricmp(current_line->opcode_txt,"LDX")) + { + if(address_mode == AM_IMMEDIATE_8) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xA2; + current_line->address_mode = AM_IMMEDIATE_8; + } + else if(address_mode == AM_IMMEDIATE_16) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xA2; + current_line->address_mode = AM_IMMEDIATE_16; + } + else if(address_mode == AM_ABSOLUTE || address_mode == AM_ABSOLUTE_LONG) /* On cast l'adressage Long en adressage Abs */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xAE; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xA6; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_Y) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xBE; + current_line->address_mode = AM_ABSOLUTE_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xB6; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_Y; + } + } + else if(!my_stricmp(current_line->opcode_txt,"LDY")) + { + if(address_mode == AM_IMMEDIATE_8) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xA0; + current_line->address_mode = AM_IMMEDIATE_8; + } + else if(address_mode == AM_IMMEDIATE_16) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xA0; + current_line->address_mode = AM_IMMEDIATE_16; + } + else if(address_mode == AM_ABSOLUTE || address_mode == AM_ABSOLUTE_LONG) /* On cast l'adressage Long en adressage Abs */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xAC; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xA4; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xBC; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xB4; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + } + else if(!my_stricmp(current_line->opcode_txt,"LSR")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x4A; + current_line->address_mode = AM_IMPLICIT; + } + else if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x4E; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x46; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x5E; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x56; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + } + else if(!my_stricmp(current_line->opcode_txt,"MVN")) + { + if(address_mode == AM_BLOCK_MOVE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x54; + current_line->address_mode = AM_BLOCK_MOVE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"MVP")) + { + if(address_mode == AM_BLOCK_MOVE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x44; + current_line->address_mode = AM_BLOCK_MOVE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"NOP")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xEA; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"ORA") || !my_stricmp(current_line->opcode_txt,"ORAL")) + { + if(address_mode == AM_IMMEDIATE_8) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x09; + current_line->address_mode = AM_IMMEDIATE_8; + } + else if(address_mode == AM_IMMEDIATE_16) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x09; + current_line->address_mode = AM_IMMEDIATE_16; + } + else if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x0D; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_ABSOLUTE_LONG) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0x0F; + current_line->address_mode = AM_ABSOLUTE_LONG; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x05; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x12; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x07; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x1D; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_LONG_INDEXED_X) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0x1F; + current_line->address_mode = AM_ABSOLUTE_LONG_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_Y || address_mode == AM_DIRECT_PAGE_INDEXED_Y) /* $08,Y doit aussi pouvoir être interpretté comme $0008,Y car DP,Y n'existe pas */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x19; + current_line->address_mode = AM_ABSOLUTE_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x15; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X_INDIRECT) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x01; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x11; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x17; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y; + } + else if(address_mode == AM_STACK_RELATIVE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x03; + current_line->address_mode = AM_STACK_RELATIVE; + } + else if(address_mode == AM_STACK_RELATIVE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x13; + current_line->address_mode = AM_STACK_RELATIVE_INDIRECT_INDEXED_Y; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PEA")) + { + if(address_mode == AM_ABSOLUTE_LONG || address_mode == AM_ABSOLUTE || address_mode == AM_DIRECT_PAGE || address_mode == AM_IMMEDIATE_8 || address_mode == AM_IMMEDIATE_16) /* On doit pouvoir écrire PEA $1234 ou PEA $0 ou PEA #0 ou PEA #$1234 */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xF4; + current_line->address_mode = AM_ABSOLUTE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PEI")) + { + if(address_mode == AM_DIRECT_PAGE_INDIRECT || address_mode == AM_DIRECT_PAGE || address_mode == AM_ABSOLUTE) /* On doit pouvoir écrire PEI $12 ou PEI ($12) ou PEI Label */ + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xD4; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PER")) + { + if(address_mode == AM_ABSOLUTE || address_mode == AM_IMMEDIATE_16) /* PER Label ou PER #Label ou PER $address => Relatif Long comme le BRL */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x62; + current_line->address_mode = AM_PC_RELATIVE_LONG; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PHA")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x48; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PHB")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x8B; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PHD")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x0B; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PHK")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x4B; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PHP")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x08; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PHX")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xDA; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PHY")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x5A; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PLA")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x68; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PLB")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xAB; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PLD")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x2B; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PLP")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x28; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PLX")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xFA; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"PLY")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x7A; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"REP")) + { + if(address_mode == AM_IMMEDIATE_8 || address_mode == AM_IMMEDIATE_16 || address_mode == AM_DIRECT_PAGE) /* On peut tomber sur du REP $30 */ + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xC2; + current_line->address_mode = AM_IMMEDIATE_8; + } + } + else if(!my_stricmp(current_line->opcode_txt,"ROL")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x2A; + current_line->address_mode = AM_IMPLICIT; + } + else if(address_mode == AM_ABSOLUTE || address_mode == AM_ABSOLUTE_LONG) /* On cast le Long en Absolute */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x2E; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x26; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x3E; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x36; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + } + else if(!my_stricmp(current_line->opcode_txt,"ROR")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x6A; + current_line->address_mode = AM_IMPLICIT; + } + else if(address_mode == AM_ABSOLUTE || address_mode == AM_ABSOLUTE_LONG) /* On cast le Long en Absolute */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x6E; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x66; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x7E; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x76; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + } + else if(!my_stricmp(current_line->opcode_txt,"RTI")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x40; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"RTL")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x6B; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"RTS")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x60; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"SBC") || !my_stricmp(current_line->opcode_txt,"SBCL")) + { + if(address_mode == AM_IMMEDIATE_8) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xE9; + current_line->address_mode = AM_IMMEDIATE_8; + } + else if(address_mode == AM_IMMEDIATE_16) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xE9; + current_line->address_mode = AM_IMMEDIATE_16; + } + else if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xED; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_ABSOLUTE_LONG) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0xEF; + current_line->address_mode = AM_ABSOLUTE_LONG; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xE5; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xF2; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xE7; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xFD; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_LONG_INDEXED_X) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0xFF; + current_line->address_mode = AM_ABSOLUTE_LONG_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_Y || address_mode == AM_DIRECT_PAGE_INDEXED_Y) /* $08,Y doit aussi pouvoir être interpretté comme $0008,Y car DP,Y n'existe pas */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0xF9; + current_line->address_mode = AM_ABSOLUTE_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xF5; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X_INDIRECT) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xE1; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xF1; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xF7; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y; + } + else if(address_mode == AM_STACK_RELATIVE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xE3; + current_line->address_mode = AM_STACK_RELATIVE; + } + else if(address_mode == AM_STACK_RELATIVE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xF3; + current_line->address_mode = AM_STACK_RELATIVE_INDIRECT_INDEXED_Y; + } + } + else if(!my_stricmp(current_line->opcode_txt,"SEC")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x38; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"SED")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xF8; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"SEI")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x78; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"SEP")) + { + if(address_mode == AM_IMMEDIATE_8 || address_mode == AM_IMMEDIATE_16 || address_mode == AM_DIRECT_PAGE) /* On peut tompber sur du SEP $20 */ + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0xE2; + current_line->address_mode = AM_IMMEDIATE_8; + } + } + else if(!my_stricmp(current_line->opcode_txt,"STA") || !my_stricmp(current_line->opcode_txt,"STAL")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x8D; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_ABSOLUTE_LONG) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0x8F; + current_line->address_mode = AM_ABSOLUTE_LONG; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x85; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT || address_mode == AM_ABSOLUTE_INDIRECT) /* Le STA ($0000) peut aussi être intepreté comme STA ($00) */ + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x92; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG || address_mode == AM_ABSOLUTE_INDIRECT_LONG) /* Le STA [$0000] peut aussi être interprété comme STA [$00] */ + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x87; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x9D; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_LONG_INDEXED_X) + { + current_line->nb_byte = 4; + current_line->opcode_byte = 0x9F; + current_line->address_mode = AM_ABSOLUTE_LONG_INDEXED_X; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_Y || address_mode == AM_DIRECT_PAGE_INDEXED_Y) /* On fait passer le $00,Y pour un $0000,Y */ + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x99; + current_line->address_mode = AM_ABSOLUTE_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x95; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X_INDIRECT) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x81; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X_INDIRECT; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x91; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_INDEXED_Y; + } + else if(address_mode == AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x97; + current_line->address_mode = AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y; + } + else if(address_mode == AM_STACK_RELATIVE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x83; + current_line->address_mode = AM_STACK_RELATIVE; + } + else if(address_mode == AM_STACK_RELATIVE_INDIRECT_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x93; + current_line->address_mode = AM_STACK_RELATIVE_INDIRECT_INDEXED_Y; + } + } + else if(!my_stricmp(current_line->opcode_txt,"STP")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xDB; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"STX")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x8E; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x86; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_Y) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x96; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_Y; + } + } + else if(!my_stricmp(current_line->opcode_txt,"STY")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x8C; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x84; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x94; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + } + else if(!my_stricmp(current_line->opcode_txt,"STZ")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x9C; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x64; + current_line->address_mode = AM_DIRECT_PAGE; + } + else if(address_mode == AM_ABSOLUTE_INDEXED_X) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x9E; + current_line->address_mode = AM_ABSOLUTE_INDEXED_X; + } + else if(address_mode == AM_DIRECT_PAGE_INDEXED_X) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x74; + current_line->address_mode = AM_DIRECT_PAGE_INDEXED_X; + } + } + else if(!my_stricmp(current_line->opcode_txt,"TAX")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xAA; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"TAY")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xA8; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"TCD")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x5B; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"TCS")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x1B; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"TDC")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x7B; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"TRB")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x1C; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x14; + current_line->address_mode = AM_DIRECT_PAGE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"TSB")) + { + if(address_mode == AM_ABSOLUTE) + { + current_line->nb_byte = 3; + current_line->opcode_byte = 0x0C; + current_line->address_mode = AM_ABSOLUTE; + } + else if(address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x04; + current_line->address_mode = AM_DIRECT_PAGE; + } + } + else if(!my_stricmp(current_line->opcode_txt,"TSC")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x3B; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"TSX")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xBA; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"TXA")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x8A; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"TXS")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x9A; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"TXY")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x9B; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"TYA")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x98; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"TYX")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xBB; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"WAI")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xCB; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"WDM")) /* Consomme 1 ou 2 octets (Signature) */ + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0x42; + current_line->address_mode = AM_IMPLICIT; + } + else if(address_mode == AM_IMMEDIATE_8 || address_mode == AM_DIRECT_PAGE) + { + current_line->nb_byte = 2; + current_line->opcode_byte = 0x42; + current_line->address_mode = AM_IMMEDIATE_8; + } + } + else if(!my_stricmp(current_line->opcode_txt,"XBA")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xEB; + current_line->address_mode = AM_IMPLICIT; + } + } + else if(!my_stricmp(current_line->opcode_txt,"XCE")) + { + if(address_mode == AM_IMPLICIT) + { + current_line->nb_byte = 1; + current_line->opcode_byte = 0xFB; + current_line->address_mode = AM_IMPLICIT; + } + } + + /* AM_UNKOWN = problème */ + if(current_line->nb_byte <= 0) + { + sprintf(param->buffer_error,"Impossible to decode address mode for instruction '%s %s' (line %d, file '%s')%s%s", + current_line->opcode_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name, + (strlen(buffer_error) > 0) ? " : ":"",buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } +} + + +/*******************************************************************************/ +/* BuildOneCodeLineOperand() : Création de l'Operand pour une ligne de Code. */ +/*******************************************************************************/ +static void BuildOneCodeLineOperand(struct source_line *current_line, int *has_error_rtn, struct omf_segment *current_omfsegment, struct omf_project *current_omfproject) +{ + int64_t operand_value_64, operand_value_1, operand_value_2; + int operand_size, operand_value, modif, delta, is_reloc_1, is_reloc_2, is_mvp_mvn, is_multi_fixed, line_address; + DWORD AddressLong_1, AddressLong_2; + WORD OffsetPatch_1, OffsetPatch_2, OffsetReference_1, OffsetReference_2; + BYTE ByteCnt_1, ByteCnt_2, BitShiftCnt_1, BitShiftCnt_2; + struct relocate_address *current_address_1; + struct relocate_address *current_address_2; + char *next_sep; + struct external *current_external_1; + struct external *current_external_2; + char buffer_error[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + strcpy(buffer_error,""); + is_mvp_mvn = 0; + is_reloc_1 = 0; + is_reloc_2 = 0; + current_external_1 = NULL; + current_external_2 = NULL; + is_multi_fixed = current_omfproject->is_multi_fixed; + + /** On a rien à faire pour les lignes sans Operand (ERR, ...) **/ + if(current_line->nb_byte == 0 || current_line->nb_byte == 1) + return; + + /*** On va nettoyer l'Operande des () [] ,X ,Y ,S... ***/ + modif = 1; + strcpy(param->buffer_operand,current_line->operand_txt); + while(modif) + { + /* Init */ + modif = 0; + + /* Supprime les ,X */ + if(strlen(param->buffer_operand) > 2) + if(param->buffer_operand[strlen(param->buffer_operand)-2] == ',' && toupper(param->buffer_operand[strlen(param->buffer_operand)-1]) == 'X') + { + param->buffer_operand[strlen(param->buffer_operand)-2] = '\0'; + modif = 1; + } + + /* Supprime les ,Y */ + if(strlen(param->buffer_operand) > 2) + if(param->buffer_operand[strlen(param->buffer_operand)-2] == ',' && toupper(param->buffer_operand[strlen(param->buffer_operand)-1]) == 'Y') + { + param->buffer_operand[strlen(param->buffer_operand)-2] = '\0'; + modif = 1; + } + + /* Supprime les ,S */ + if(strlen(param->buffer_operand) > 2) + if(param->buffer_operand[strlen(param->buffer_operand)-2] == ',' && toupper(param->buffer_operand[strlen(param->buffer_operand)-1]) == 'S') + { + param->buffer_operand[strlen(param->buffer_operand)-2] = '\0'; + modif = 1; + } + + /* Supprime les () */ + if(strlen(param->buffer_operand) > 2) + if(param->buffer_operand[0] == '(' && param->buffer_operand[strlen(param->buffer_operand)-1] == ')') + { + memmove(¶m->buffer_operand[0],¶m->buffer_operand[1],strlen(¶m->buffer_operand[1])+1); + param->buffer_operand[strlen(param->buffer_operand)-1] = '\0'; + modif = 1; + } + + /* Supprime les [] */ + if(strlen(param->buffer_operand) > 2) + if(param->buffer_operand[0] == '[' && param->buffer_operand[strlen(param->buffer_operand)-1] == ']') + { + memmove(¶m->buffer_operand[0],¶m->buffer_operand[1],strlen(¶m->buffer_operand[1])+1); + param->buffer_operand[strlen(param->buffer_operand)-1] = '\0'; + modif = 1; + } + } + + /* Taille de l'Operand */ + operand_size = current_line->nb_byte-1; + + /** Calcule la valeur de l'Operand **/ + next_sep = strchr(param->buffer_operand,','); + if((!my_stricmp(current_line->opcode_txt,"MVN") || !my_stricmp(current_line->opcode_txt,"MVP")) && next_sep != NULL) + { + /** Attention, les MVN/MVP ont deux expressions **/ + *next_sep = '\0'; + + /* Expression 1 */ + operand_value_1 = EvalExpressionAsInteger(param->buffer_operand,buffer_error,current_line,1,&is_reloc_1,&ByteCnt_1,&BitShiftCnt_1,&OffsetReference_1,&AddressLong_1,¤t_external_1,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Impossible to evaluate Operand '%s' for instruction '%s %s' (line %d, file '%s') : %s", + param->buffer_operand,current_line->opcode_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Expression 2 */ + operand_value_2 = EvalExpressionAsInteger(next_sep+1,buffer_error,current_line,1,&is_reloc_2,&ByteCnt_2,&BitShiftCnt_2,&OffsetReference_2,&AddressLong_2,¤t_external_2,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Impossible to evaluate Operand '%s' for instruction '%s %s' (line %d, file '%s') : %s", + param->buffer_operand,current_line->opcode_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /** On fusionne les 2 en ne prenant que les octets valides **/ + operand_value_64 = (int64_t) BuildBestMVXWord((DWORD)operand_value_1,(DWORD)operand_value_2); + + /* On signale qu'on gère un MVP / MVN */ + is_mvp_mvn = 1; + } + else + { + /** Cet Opcode n'a qu'une seule expression pour l'Operande **/ + operand_value_64 = EvalExpressionAsInteger(param->buffer_operand,buffer_error,current_line,operand_size,&is_reloc_1,&ByteCnt_1,&BitShiftCnt_1,&OffsetReference_1,&AddressLong_1,¤t_external_1,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Impossible to evaluate Operand '%s' for instruction '%s %s' (line %d, file '%s') : %s", + param->buffer_operand,current_line->opcode_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Pas d'adressage Page Direct si on a un Bank != 0 */ + if((operand_value_64 & 0xFF0000) != 0 && current_line->no_direct_page == 0) + current_line->no_direct_page = 1; + } + + /** On va modifier la valeur en fonction du mode d'adressage **/ + if(current_line->address_mode == AM_PC_RELATIVE) + { + /* On élimine la partie haute de l'adresse 00Bank/ */ + operand_value = (int) (0xFFFF & operand_value_64); + + /* On regarde si on saute vers le haut ou vers le bas (+/- 8 bit) */ + if((current_line->address+2) > operand_value) + { + delta = (current_line->address+2) - operand_value; + if(delta > 128) + { + /* Première erreur rencontrée */ + if(*has_error_rtn == 0) + { + sprintf(param->buffer_latest_error,"Bad Jump for instruction '%s %s' (line %d, file '%s') : Too long", + current_line->opcode_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name); + *has_error_rtn = 1; + } + /* Valeur en erreur */ + operand_value = 0x00; + } + else + operand_value = 256 - delta; + } + else + { + delta = operand_value - (current_line->address+2); + if(delta > 127) + { + /* Première erreur rencontrée */ + if(*has_error_rtn == 0) + { + sprintf(param->buffer_latest_error,"Bad Jump for instruction '%s %s' (line %d, file '%s') : Too long", + current_line->opcode_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name); + *has_error_rtn = 1; + } + /* Valeur en erreur */ + operand_value = 0x00; + } + else + operand_value = delta; + } + } + else if(current_line->address_mode == AM_PC_RELATIVE_LONG) + { + /* On élimine la partie haute de l'adresse 00Bank/ */ + operand_value = (int) (0xFFFF & operand_value_64); + + /* On regarde si on saute vers le haut ou vers le bas (+/- 16 bit) */ + if((current_line->address+3) > operand_value) + { + delta = (current_line->address+3) - operand_value; + if(delta > 32768) + { + /* Première erreur rencontrée */ + if(*has_error_rtn == 0) + { + sprintf(param->buffer_latest_error,"Bad Jump for instruction '%s %s' (line %d, file '%s') : Too long", + current_line->opcode_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name); + *has_error_rtn = 1; + } + /* Valeur en erreur */ + operand_value = 0x0000; + } + else + operand_value = 65536 - delta; + } + else + { + delta = operand_value - (current_line->address+3); + if(delta > 32767) + { + /* Première erreur rencontrée */ + if(*has_error_rtn == 0) + { + sprintf(param->buffer_latest_error,"Bad Jump for instruction '%s %s' (line %d, file '%s') : Too long", + current_line->opcode_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name); + *has_error_rtn = 1; + } + /* Valeur en erreur */ + operand_value = 0x0000; + } + else + operand_value = delta; + } + } + else + operand_value = (int) (0xFFFFFFFF & operand_value_64); /* Garde les 32 bits */ + + /*************************************/ + /** Place les octets de l'Operand **/ + /*************************************/ + /* Conserve la valeur d'origine */ + current_line->operand_value = operand_value; + /* Tronque en fonction de nb de byte attendus */ + current_line->operand_byte[0] = (unsigned char) (operand_value & 0x0000FF); + if(operand_size > 1) + current_line->operand_byte[1] = (unsigned char) ((operand_value >> 8) & 0x0000FF); + if(operand_size > 2) + current_line->operand_byte[2] = (unsigned char) ((operand_value >> 16) & 0x0000FF); + + /* Conserve l'adresse sur 24 bit pour trancher les adresses DP */ + current_line->operand_address_long = AddressLong_1; + current_line->external_address = NULL; + + /**************************/ + /** Adresse Relogeable **/ + /**************************/ + if((is_reloc_1 == 1 || is_reloc_2 == 1) && current_line->address_mode != AM_PC_RELATIVE && current_line->address_mode != AM_PC_RELATIVE_LONG) + { + /* L'adresse de l'operande est relogeable */ + current_line->address_is_rel = 1; + + /* Les MV* peuvent avoir jusqu'à 2 adresses relogeables */ + if(is_reloc_1 == 1) + { + /* L'adresse de la ligne tient compte des [ORG $Addr ORG] */ + if(current_line->is_fix_address == 1 && current_line->address != current_line->global_address) + line_address = current_line->global_address; + else + line_address = current_line->address; + + /* Pour les MVN / MVP, la première addresse se trouve à +2 */ + OffsetPatch_1 = line_address + 1 + ((is_mvp_mvn==1)?1:0); + current_address_1 = BuildRelocateAddress(ByteCnt_1,BitShiftCnt_1,OffsetPatch_1,OffsetReference_1,current_external_1,current_omfsegment); + current_address_1->object_line = ¤t_line->operand_byte[0+((is_mvp_mvn==1)?1:0)]; + + /* On va conserver un pointeur vers l'adresse (évite de basculer en adressage Page Direct pour les EXT) */ + if(current_external_1 != NULL) + current_line->external_address = current_address_1; + } + if(is_reloc_2 == 1) + { + /* L'adresse de la ligne tient compte des [ORG $Addr ORG] */ + if(current_line->is_fix_address == 1 && current_line->address != current_line->global_address) + line_address = current_line->global_address; + else + line_address = current_line->address; + + /* Une deuxième addresse à reloger : MVN ou MVP */ + OffsetPatch_2 = line_address + 1; + current_address_2 = BuildRelocateAddress(ByteCnt_2,BitShiftCnt_2,OffsetPatch_2,OffsetReference_2,current_external_2,current_omfsegment); + current_address_2->object_line = ¤t_line->operand_byte[0]; + } + + /** On prépare ce qui va être affiché dans le fichier Output.txt **/ + if(is_reloc_1 == 1 && is_reloc_2 == 0) + { + sprintf(current_line->reloc,"%c %d",(current_external_1==NULL)?' ':'E',ByteCnt_1); + if(BitShiftCnt_1 == 0xF0) + strcat(current_line->reloc," >>16 "); + else if(BitShiftCnt_1 == 0xF8) + strcat(current_line->reloc," >> 8 "); + else + strcat(current_line->reloc," "); + } + else if(is_reloc_1 == 0 && is_reloc_2 == 1) + { + sprintf(current_line->reloc,"%c %d",(current_external_2==NULL)?' ':'E',ByteCnt_2); + if(BitShiftCnt_2 == 0xF0) + strcat(current_line->reloc," >>16 "); + else if(BitShiftCnt_2 == 0xF8) + strcat(current_line->reloc," >> 8 "); + else + strcat(current_line->reloc," "); + } + else /* Les 2 sont relogeables => on prend la première */ + { + sprintf(current_line->reloc,"%c %d",(current_external_1==NULL)?' ':'E',ByteCnt_1); + if(BitShiftCnt_1 == 0xF0) + strcat(current_line->reloc," >>16 "); + else if(BitShiftCnt_1 == 0xF8) + strcat(current_line->reloc," >> 8 "); + else + strcat(current_line->reloc," "); + } + } + else + current_line->address_is_rel = 0; +} + + +/**********************************************************/ +/* DecodeAddressMode() : Détermine le mode d'adressage. */ +/**********************************************************/ +static int DecodeAddressMode(struct source_line *current_line, char *error_buffer_rtn, struct omf_segment *current_omfsegment) +{ + int i, j, nb_byte, nb_byte_left, nb_byte_right, is_address; + char *next_char; + char operand[1024]; + + /* On recopie l'Opérande pour le travailler (on supprime les {}) */ + for(i=0,j=0; i<(int)strlen(current_line->operand_txt); i++) + if(current_line->operand_txt[i] != '{' && current_line->operand_txt[i] != '}') + operand[j++] = current_line->operand_txt[i]; + operand[j] = '\0'; + + /****************/ + /** Implicit **/ + /****************/ + if(strlen(operand) == 0 || !my_stricmp(operand,"A")) + return(AM_IMPLICIT); + + /*****************/ + /** Indexed X **/ + /*****************/ + if(strlen(operand) > 2) + if(!my_stricmp(&operand[strlen(operand)-2],",X")) + { + /* Supprime le ,X */ + operand[strlen(operand)-2] = '\0'; + + /** $@,X $@@,X ou $@@@,X **/ + nb_byte = GetOperandNbByte(operand,current_line,&is_address,error_buffer_rtn,current_omfsegment); + if(nb_byte == 1 && current_line->no_direct_page == 0) + return(AM_DIRECT_PAGE_INDEXED_X); + else if(nb_byte == 2 || (nb_byte == 1 && current_line->no_direct_page == 1)) + return(AM_ABSOLUTE_INDEXED_X); + else if(nb_byte == 3) + return(AM_ABSOLUTE_LONG_INDEXED_X); + + /* Inconnu */ + return(AM_UNKOWN); + } + + /*****************/ + /** Indexed Y **/ + /*****************/ + if(strlen(operand) > 2) + if(!my_stricmp(&operand[strlen(operand)-2],",Y")) + { + /* Supprime le ,Y */ + operand[strlen(operand)-2] = '\0'; + + /** [$@],Y : DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y **/ + if(strlen(operand) > 2) + if(operand[0] == '[' && operand[strlen(operand)-1] == ']') + { + /* Supprime les [] */ + operand[strlen(operand)-1] = '\0'; + memmove(&operand[0],&operand[1],strlen(&operand[1])+1); + + /* Vérifie s'il s'agit d'une Page Direct */ + nb_byte = GetOperandNbByte(operand,current_line,&is_address,error_buffer_rtn,current_omfsegment); + if(nb_byte == 1 || nb_byte == 2 || nb_byte == 3) + return(AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y); /* De toute façon il n'y a que celui-là */ + + /* Inconnu */ + return(AM_UNKOWN); + } + + /** (@,S),Y : STACK_RELATIVE_INDIRECT_INDEXED_Y **/ + if(strlen(operand) > 4) + if(operand[0] == '(' && operand[strlen(operand)-3] == ','&& toupper(operand[strlen(operand)-2]) == 'S' && operand[strlen(operand)-1] == ')') + { + /* Supprime les (,S) */ + operand[strlen(operand)-3] = '\0'; + memmove(&operand[0],&operand[1],strlen(&operand[1])+1); + + /* Vérifie s'il s'agit d'une Pile */ + nb_byte = GetOperandNbByte(operand,current_line,&is_address,error_buffer_rtn,current_omfsegment); + if(nb_byte == 1) + return(AM_STACK_RELATIVE_INDIRECT_INDEXED_Y); + + /* Inconnu */ + return(AM_UNKOWN); + } + + /** ($@),Y : DIRECT_PAGE_INDIRECT_INDEXED_Y **/ + if(strlen(operand) > 2) + if(operand[0] == '(' && operand[strlen(operand)-1] == ')') + { + /* Supprime les () */ + operand[strlen(operand)-1] = '\0'; + memmove(&operand[0],&operand[1],strlen(&operand[1])+1); + + /* Vérifie s'il s'agit d'une Page Direct (on peut avoir un Label en Page Direct) */ + nb_byte = GetOperandNbByte(operand,current_line,&is_address,error_buffer_rtn,current_omfsegment); + if(nb_byte == 1 || nb_byte == 2) + return(AM_DIRECT_PAGE_INDIRECT_INDEXED_Y); + + /* Inconnu */ + return(AM_UNKOWN); + } + + /** On doit choisir entre $@,Y et $@@,Y **/ + nb_byte = GetOperandNbByte(operand,current_line,&is_address,error_buffer_rtn,current_omfsegment); + if(nb_byte == 1 && current_line->no_direct_page == 0) + return(AM_DIRECT_PAGE_INDEXED_Y); + else if(nb_byte == 2 || (nb_byte == 1 && current_line->no_direct_page == 1)) + return(AM_ABSOLUTE_INDEXED_Y); + + /* Inconnu */ + return(AM_UNKOWN); + } + + /**********************/ + /** Stack Relative **/ + /**********************/ + if(strlen(operand) > 2) + if(!my_stricmp(&operand[strlen(operand)-2],",S")) + { + /* Supprime le ,S */ + operand[strlen(operand)-2] = '\0'; + + /* @,S : Vérifie s'il s'agit d'une Pile */ + nb_byte = GetOperandNbByte(operand,current_line,&is_address,error_buffer_rtn,current_omfsegment); + if(nb_byte == 1) + return(AM_STACK_RELATIVE); + + /* Inconnu */ + return(AM_UNKOWN); + } + + /****************/ + /** Indirect **/ + /****************/ + if(strlen(operand) > 2) + if(operand[0] == '(' && operand[strlen(operand)-1] == ')') + { + /* Supprime les () */ + operand[strlen(operand)-1] = '\0'; + memmove(&operand[0],&operand[1],strlen(&operand[1])+1); + + /** X INDEXED **/ + if(strlen(operand) > 2) + if(operand[strlen(operand)-2] == ',' && toupper(operand[strlen(operand)-1]) == 'X') + { + /* Supprime le ,X */ + operand[strlen(operand)-2] = '\0'; + + /** On doit choisir entre ($@,X) et ($@@,X) **/ + nb_byte = GetOperandNbByte(operand,current_line,&is_address,error_buffer_rtn,current_omfsegment); + if(nb_byte == 1 && current_line->no_direct_page == 0) + return(AM_DIRECT_PAGE_INDEXED_X_INDIRECT); + else if(nb_byte == 2 || (nb_byte == 1 && current_line->no_direct_page == 1)) + return(AM_ABSOLUTE_INDEXED_X_INDIRECT); + + /* Inconnu */ + return(AM_UNKOWN); + } + + /** On doit choisir entre ($@) et ($@@) **/ + nb_byte = GetOperandNbByte(operand,current_line,&is_address,error_buffer_rtn,current_omfsegment); + if(nb_byte == 1 && current_line->no_direct_page == 0) + return(AM_DIRECT_PAGE_INDIRECT); + else + return(AM_ABSOLUTE_INDIRECT); + + /* Inconnu */ + return(AM_UNKOWN); + } + + /*********************/ + /** Indirect Long **/ + /*********************/ + if(strlen(operand) > 2) + if(operand[0] == '[' && operand[strlen(operand)-1] == ']') + { + /* Supprime les () */ + operand[strlen(operand)-1] = '\0'; + memmove(&operand[0],&operand[1],strlen(&operand[1])+1); + + /** On doit choisir entre [$@] et [$@@] **/ + nb_byte = GetOperandNbByte(operand,current_line,&is_address,error_buffer_rtn,current_omfsegment); + if(nb_byte == 1 && current_line->no_direct_page == 0) + return(AM_DIRECT_PAGE_INDIRECT_LONG); + else + return(AM_ABSOLUTE_INDIRECT_LONG); + + /* Inconnu */ + return(AM_UNKOWN); + } + + /********************/ + /** Block Move **/ + /********************/ + next_char = strchr(operand,','); + if(next_char != NULL) + { + /* On supprime la , */ + *next_char = '\0'; + + /* Vérifie ce qui est de chaque côté de la , */ + nb_byte_left = GetOperandNbByte(operand,current_line,&is_address,error_buffer_rtn,current_omfsegment); + nb_byte_right = GetOperandNbByte(next_char+1,current_line,&is_address,error_buffer_rtn,current_omfsegment); + + /* On a reconnu un MVN|MVP src,dst */ + if((nb_byte_left == 1 || nb_byte_left == 2 || nb_byte_left == 3) && + (nb_byte_right == 1 || nb_byte_right == 2 || nb_byte_right == 3)) + return(AM_BLOCK_MOVE); + + /* Inconnu */ + return(AM_UNKOWN); + } + + /*******************************/ + /** $Absolute ou #Immediate **/ + /*******************************/ + nb_byte = GetOperandNbByte(operand,current_line,&is_address,error_buffer_rtn,current_omfsegment); + if(nb_byte > 0) + { + /** $Absolute **/ + if(is_address == 1) + { + /** On doit choisir entre $@, $@@ et $@@@ **/ + if(nb_byte == 1 && current_line->no_direct_page == 0) + return(AM_DIRECT_PAGE); + else if(nb_byte == 2 || (nb_byte == 1 && current_line->no_direct_page == 1)) + return(AM_ABSOLUTE); + else if(nb_byte == 3) + return(AM_ABSOLUTE_LONG); + } + else /** #Immediate **/ + { + /** On doit choisir entre #@ et #@@ **/ + if(nb_byte == 1) + return(AM_IMMEDIATE_8); + else if(nb_byte == 2) + return(AM_IMMEDIATE_16); + } + } + + /***************/ + /** Unknown **/ + /***************/ + return(AM_UNKOWN); +} + + +/****************************************************************************************************************/ +/* GetOperandNbByte() : Détermine le nombre d'octets d'un Operande et son Type (valeur ou adresse à patcher). */ +/****************************************************************************************************************/ +static int GetOperandNbByte(char *operand, struct source_line *current_line, int *is_address_rtn, char *buffer_error_rtn, struct omf_segment *current_omfsegment) +{ + int i, nb_element, nb_max_byte, nb_byte, bit_mode, value_format, has_extra_dash; + int has_dash, has_less, has_more, has_exp, has_pipe, has_long_addr, is_block_copy; + int nb_address, is_address; + char **tab_element; + + /* Init */ + nb_max_byte = 0; + nb_address = 0; + has_long_addr = 0; + is_block_copy= 0; + is_address = 1; + *is_address_rtn = 0; + strcpy(buffer_error_rtn,""); + + /* Chaine vide : Pas d'opérand */ + if(strlen(operand) == 0) + return(0); + + /* Adressage Long ? (LDAL, STAL...) */ + if(!my_stricmp(current_line->opcode_txt,"ADCL") || !my_stricmp(current_line->opcode_txt,"ANDL") || !my_stricmp(current_line->opcode_txt,"CMPL") || + !my_stricmp(current_line->opcode_txt,"EORL") || !my_stricmp(current_line->opcode_txt,"JML") || !my_stricmp(current_line->opcode_txt,"JMPL") || + !my_stricmp(current_line->opcode_txt,"LDAL") || !my_stricmp(current_line->opcode_txt,"ORAL") || !my_stricmp(current_line->opcode_txt,"SBCL") || + !my_stricmp(current_line->opcode_txt,"STAL")) + has_long_addr = 1; + + /* Copy de Block ? (MVN, MVP) */ + if(!my_stricmp(current_line->opcode_txt,"MVN") || !my_stricmp(current_line->opcode_txt,"MVP")) + is_block_copy = 1; + + /** On va traiter les # < > ^ | **/ + has_dash = (operand[0] == '#') ? 1 : 0; + has_less = (operand[has_dash] == '<') ? 1 : 0; + has_more = (operand[has_dash] == '>') ? 1 : 0; + has_exp = (operand[has_dash] == '^') ? 1 : 0; + has_pipe = (operand[has_dash] == '|' || operand[has_dash] == '!') ? 1 : 0; + + /** Découpe la chaine de caractères en plusieurs éléments (saute les #><^| du début) **/ + tab_element = DecodeOperandeAsElementTable(&operand[has_dash+has_less+has_more+has_exp+has_pipe],&nb_element,SEPARATOR_EVALUATE_EXPRESSION,current_line); + if(tab_element == NULL) + { + sprintf(buffer_error_rtn,"Impossible to decode Operand '%s' as element table",operand); + return(0); + } + + /** On va gérer le - au début => Ca ne change rien pour le nombre de byte de l'expression, on le supprime **/ + if(!strcmp(tab_element[0],"-") && nb_element > 1) + { + /* On peut supprimer le - */ + free(tab_element[0]); + for(i=1; i 0) + if(nb_address % 2 == 0) + is_address = 0; + if(has_dash == 1) + is_address = 0; + + /** 0 byte => erreur **/ + if(nb_max_byte == 0) + { + sprintf(buffer_error_rtn,"Can't get length (in byte) for Operand '%s'",operand); + *is_address_rtn = is_address; + return(0); + } + + /** On va ajuster la taille de la DATA en fonction du MX **/ + if(is_address == 0) + { + bit_mode = GetBitMode(current_line); + if(bit_mode == 8) + nb_max_byte = 1; + else if(bit_mode == 16) + nb_max_byte = 2; + } + else + { + /* On ajuste l'adresse en fonction du > et du | */ + if(has_more == 1) + { + current_line->no_direct_page = 1; + nb_max_byte = 3; + } + if(has_pipe == 1) + { + current_line->no_direct_page = 1; + nb_max_byte = 2; + } + + /* Adressage Long (LDAL, STAL...) */ + if(has_long_addr == 1) + { + current_line->no_direct_page = 1; + nb_max_byte = 3; + } + if(is_block_copy == 0 && has_long_addr == 0 && has_more == 0 && nb_max_byte == 3) /* L'adressage long n'est valable que si on a mis du L ou du > (ou pour les MVP / MVN) */ + nb_max_byte = 2; + + /* On a demandé un compactage => On va mettre du Page Direct à la place du Absolute */ + if(nb_max_byte == 2 && current_line->use_direct_page == 1) + nb_max_byte = 1; + } + + /* Renvoie le nombre d'octets de l'Operand (1 2 ou 3) */ + *is_address_rtn = is_address; + return(nb_max_byte); +} + + +/*******************************************************/ +/* GetBitMode(): Détermine si on est en 8 ou 16 bit. */ +/*******************************************************/ +static int GetBitMode(struct source_line *current_line) +{ + /** Registre X ou Y **/ + if(toupper(current_line->opcode_txt[strlen(current_line->opcode_txt)-1]) == 'X' || + toupper(current_line->opcode_txt[strlen(current_line->opcode_txt)-1]) == 'Y') + { + /* Emulation or Native */ + if(current_line->x[0] == '1') + return(8); + else if(current_line->x[0] == '0') + return(16); + else + return(0); + } + else /** Accumulator **/ + { + /* Emulation or Native */ + if(current_line->m[0] == '1') + return(8); + else if(current_line->m[0] == '0') + return(16); + else + return(0); + } +} + + +/************************************************************************************************************/ +/* CompactDirectPageCode() : On passe toutes les lignes en revue pour détecter les adressages Page Direct. */ +/************************************************************************************************************/ +int CompactDirectPageCode(struct omf_segment *current_omfsegment) +{ + int has_compact; + struct source_file *first_file; + struct source_line *current_line; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + has_compact = 0; + + /* Récupère le 1er fichier source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + if(first_file == NULL) + return(0); + + /*** Passe en revue toutes les lignes pour créer le code binaire de l'Operand ***/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* Cette ligne n'est pas valide */ + if(current_line->is_valid == 0 || current_line->is_dum == 1 || current_line->type != LINE_CODE) + continue; + if(current_line->no_direct_page == 1) + continue; + if(!IsPageDirectOpcode(current_line->opcode_txt)) + continue; + if(current_line->address_is_rel == 1) /* L'adresse est relogeable (OMF) */ + continue; + if(current_line->nb_byte != 3) /* Operand Size = nb_byte-1 */ + continue; + if(current_line->address_mode <= AM_IMPLICIT || current_line->address_mode >= AM_ABSOLUTE_LONG) + continue; + if(current_line->external_address != NULL) /* Cette addresse est située dans un autre Segment */ + continue; + + /** On ne va considérer que les adressages fixes $0000/$00FF (ou celles dans un OMF mais venant via un DUM) **/ + if(current_line->operand_byte[1] == 0x00 && current_line->operand_byte[2] == 0x00 && current_line->use_direct_page == 0) + { + current_line->use_direct_page = 1; + has_compact = 1; + } + } + + + /* OK */ + return(has_compact); +} + +/***********************************************************************/ diff --git a/Source/a65816_Code.h b/Source/a65816_Code.h new file mode 100644 index 0000000..fb16d55 --- /dev/null +++ b/Source/a65816_Code.h @@ -0,0 +1,13 @@ +/***********************************************************************/ +/* */ +/* a65816_Code.h : Header pour la génération du Code objet. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +int BuildAllCodeLineSize(struct omf_segment *current_omfsegment); +int BuildAllCodeLine(int *,struct omf_segment *current_omfsegment,struct omf_project *); +int CompactDirectPageCode(struct omf_segment *current_omfsegment); + +/***********************************************************************/ diff --git a/Source/a65816_Cond.c b/Source/a65816_Cond.c new file mode 100644 index 0000000..ca6d8b4 --- /dev/null +++ b/Source/a65816_Cond.c @@ -0,0 +1,219 @@ +/***********************************************************************/ +/* */ +/* a65816_Cond.c : Module pour la gestion des Conditional. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Dc_Library.h" +#include "a65816_File.h" +#include "a65816_Line.h" +#include "a65816_Cond.h" + +/****************************************************************************/ +/* ProcessConditionalDirective() : Traite les lignes avec des conditions. */ +/****************************************************************************/ +int ProcessConditionalDirective(struct omf_segment *current_omfsegment) +{ + BYTE byte_count, bit_shift; + WORD offset_reference; + DWORD address_long; + int64_t value_64; + int value, level, is_reloc; + struct source_file *first_file; + struct source_line *begin_line; + struct source_line *end_line; + struct source_line *current_line; + struct source_line *next_line; + struct external *current_external; + char buffer_error[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + level = 0; + + /* Récupère le 1er fichier source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + if(first_file == NULL) + return(0); + + /*** Passe en revue toutes les lignes pour calculer le niveau des IF/ELSE/FIN DO/ELSE/FIN ***/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ne va ignorer les lignes invalides et les Macros définies dans le fichier Source */ + if(current_line->is_valid == 0 || current_line->is_inside_macro == 1) + continue; + + /** On va devoir gérer les variables en dehors de Lup pour calculer leur valeur **/ + if(current_line->type == LINE_DIRECTIVE && (!my_stricmp(current_line->opcode_txt,"DO") || !my_stricmp(current_line->opcode_txt,"IF"))) + { + /* Augmente le niveau */ + current_line->cond_level = level; + level++; + } + else if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"ELSE")) + { + /* Erreur */ + if(level == 0) + { + sprintf(param->buffer_error,"Error : Conditional ELSE without IF or DO before (line %d from file '%s')",current_line->file_line_number,current_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* On est dans une condition */ + current_line->cond_level = level-1; + } + else if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"FIN")) + { + /* Erreur */ + if(level == 0) + printf(" Warning : Conditional FIN without IF or DO before (line %d from file '%s')\n",current_line->file_line_number,current_line->file->file_name); + else + { + /* Baisse le niveau */ + level--; + current_line->cond_level = level; + } + } + else + current_line->cond_level = level; + } + + /* On vérifie qu'on est bien à 0 */ + if(level != 0) + { + sprintf(param->buffer_error,"Error : Missing %d FIN conditional in source code",level); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /** On va évaluer les Conditions **/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ne va ignorer les lignes invalides */ + if(current_line->is_valid == 0 || current_line->is_inside_macro == 1) + continue; + + /*** On traite un block de IF/DO ELSE FIN pour déterminer la partie valide ***/ + if(current_line->type == LINE_DIRECTIVE && (!my_stricmp(current_line->opcode_txt,"DO") || !my_stricmp(current_line->opcode_txt,"IF"))) + { + /* Evaluation du DO */ + if(!my_stricmp(current_line->opcode_txt,"DO")) + { + /* On évalue la condition à 0 ou 1 */ + value_64 = EvalExpressionAsInteger(current_line->operand_txt,buffer_error,current_line,current_line->nb_byte-1,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Impossible to evaluate DO conditional part '%s' (line %d from file '%s') : %s",current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Conversion en 0 / 1 */ + value = (value_64 == 0) ? 0 : 1; + } + else if(!my_stricmp(current_line->opcode_txt,"IF")) + { + /* MX */ + if(!my_strnicmp(current_line->operand_txt,"MX",2)) + { + /* Evaluation de l'expression */ + value_64 = EvalExpressionAsInteger(current_line->operand_txt,buffer_error,current_line,current_line->nb_byte-1,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Impossible to evaluate IF conditional part '%s' (line %d from file '%s') : %s",current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + /* Conversion en 0 / 1 */ + value = (value_64 == 0) ? 0 : 1; + } + else /* First character */ + { + /* Evaluation de l'expression */ + value = 0; + if(strlen(current_line->operand_txt) >= 3) + if(current_line->operand_txt[0] == current_line->operand_txt[2]) + value = 1; + } + } + + /** On va marquer les lignes suivantes **/ + current_line->is_valid = 1; /* La ligne IF/DO est valide */ + for(next_line=current_line->next; next_line; next_line=next_line->next) + { + if(next_line->type == LINE_DIRECTIVE && !my_stricmp(next_line->opcode_txt,"ELSE") && next_line->cond_level == current_line->cond_level) + { + /* Inverse */ + value = (value == 0) ? 1 : 0; + next_line->is_valid = 1; /* La ligne ELSE du IF/DO est valide */ + } + else if(next_line->type == LINE_DIRECTIVE && !my_stricmp(next_line->opcode_txt,"FIN") && next_line->cond_level == current_line->cond_level) + { + /* Fin du block */ + next_line->is_valid = 1; /* La ligne FIN du IF/DO est valide */ + break; + } + else + next_line->is_valid = value; /* La validité des lignes à l'intérieur dépend de l'évaluation de la condition */ + } + + /* On va passer à la condition suivante (on va évaluer les IF présent dans la partie valide de ce IF) */ + } + else + current_line->is_valid = 1; /* Par défaut les lignes sont valides */ + } + + /** On va marquer les zones Lup comme non valides **/ + for(begin_line=first_file->first_line; begin_line; begin_line=begin_line->next) + { + /* On ignore les lignes invalides */ + if(begin_line->is_valid == 0 || begin_line->is_inside_macro == 1) + continue; + + if(begin_line->type == LINE_DIRECTIVE && !my_stricmp(begin_line->opcode_txt,"LUP")) + { + /** Recherche la fin de la Lup **/ + for(end_line=begin_line->next; end_line; end_line=end_line->next) + if(end_line->type == LINE_DIRECTIVE && !my_stricmp(end_line->opcode_txt,"--^")) + break; + else if(end_line->type == LINE_DIRECTIVE && !my_stricmp(end_line->opcode_txt,"LUP")) + { + /* Erreur : On commence une nouvelle alors que la précédente n'est pas terminé */ + sprintf(param->buffer_error,"Impossible to locate end of Lup '--^', line %d from file '%s'",begin_line->file_line_number,begin_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Rien trouvé ? */ + if(end_line == NULL) + { + sprintf(param->buffer_error,"Impossible to locate end of Lup '--^', line %d from file '%s'",begin_line->file_line_number,begin_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /** Marques les lignes de la Lup comme invalides (sauf celles présentes dans les Macros du Code) **/ + for(current_line=begin_line; current_line != end_line->next; current_line=current_line->next) + current_line->is_valid = 0; + + /* On continue à la fin de la zone */ + begin_line = end_line; + } + } + + /* OK */ + return(0); +} + +/***********************************************************************/ \ No newline at end of file diff --git a/Source/a65816_Cond.h b/Source/a65816_Cond.h new file mode 100644 index 0000000..fe5b08c --- /dev/null +++ b/Source/a65816_Cond.h @@ -0,0 +1,11 @@ +/***********************************************************************/ +/* */ +/* a65816_Cond.h : Header pour la gestion des Conditional. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +int ProcessConditionalDirective(struct omf_segment *); + +/***********************************************************************/ diff --git a/Source/a65816_Data.c b/Source/a65816_Data.c new file mode 100644 index 0000000..0e42f13 --- /dev/null +++ b/Source/a65816_Data.c @@ -0,0 +1,717 @@ +/***********************************************************************/ +/* */ +/* a65816_Code.c : Module pour la génération du code objet. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +#include +#include +#include +#include +#include + +#include "Dc_Library.h" +#include "a65816_Line.h" +#include "a65816_File.h" +#include "a65816_Macro.h" +#include "a65816_Data.h" + + +static void BuildOneDataLineSize(struct source_line *,char *,struct omf_segment *); +static void BuildOneDataLineOperand(struct source_line *,char *,struct omf_segment *); + +/*************************************************************************/ +/* BuildAllDataLineSize() : Calcule de la taille pour les lignes Data. */ +/*************************************************************************/ +int BuildAllDataLineSize(struct omf_segment *current_omfsegment) +{ + struct source_file *first_file; + struct source_line *current_line; + char buffer_error[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Récupère le 1er fichier source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + if(first_file == NULL) + return(0); + + /*** Passe en revue toutes les lignes Data pour calculer leur taille ***/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* Cette ligne n'est pas valide */ + if(current_line->is_valid == 0) + { + current_line->nb_byte = 0; + continue; + } + + /** Lignes de Data **/ + if(current_line->type == LINE_DATA) + { + /** Détermine la taille de Operand **/ + BuildOneDataLineSize(current_line,buffer_error,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Impossible to decode Data format for instruction '%s %s' (line %d, file '%s') : %s", + current_line->opcode_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /** Allocation mémoire pour les Data **/ + current_line->data = (unsigned char *) calloc(current_line->nb_byte+1,sizeof(unsigned char)); + if(current_line->data == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to store Data line '%s %s' (line %d, file '%s')", + current_line->opcode_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + } + } + + /* OK */ + return(0); +} + + +/*************************************************************************/ +/* BuildAllDataLineSize() : Calcule de la taille pour les lignes Data. */ +/*************************************************************************/ +int BuildAllDataLine(struct omf_segment *current_omfsegment) +{ + struct source_file *first_file; + struct source_line *current_line; + char buffer_error[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Récupère le 1er fichier source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + if(first_file == NULL) + return(0); + + /*** Passe en revue toutes les lignes Data pour créer l'Operand ***/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* Cette ligne n'est pas valide */ + if(current_line->is_valid == 0 || current_line->is_dum == 1) + continue; + + /** Lignes de Data **/ + if(current_line->type == LINE_DATA) + { + /** Création des données de l'Operand **/ + BuildOneDataLineOperand(current_line,buffer_error,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Impossible to build Data line '%s %s' (line %d, file '%s') : %s", + current_line->opcode_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + } + else if(current_line->type == LINE_VARIABLE) + { + /** Evaluation de la variable **/ + EvaluateVariableLine(current_line,current_omfsegment); + } + } + + /* OK */ + return(0); +} + + +/********************************************************************/ +/* BuildOneDataLineSize() : Détermine la taille d'une ligne DATA. */ +/********************************************************************/ +static void BuildOneDataLineSize(struct source_line *current_line, char *buffer_error_rtn, struct omf_segment *current_omfsegment) +{ + BYTE byte_count, bit_shift; + WORD offset_reference; + DWORD address_long; + int i, nb_element, nb_valid_element, nb_byte, nb_nibble, length, is_reloc; + char *next_char; + char **tab_element; + struct external *current_external; + char buffer_error[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + strcpy(buffer_error_rtn,""); + + /*** On va reconnaitre les différents types de Data ***/ + if(!my_stricmp(current_line->opcode_txt,"DA") || !my_stricmp(current_line->opcode_txt,"DW") || !my_stricmp(current_line->opcode_txt,"DDB") || + !my_stricmp(current_line->opcode_txt,"DFB") || !my_stricmp(current_line->opcode_txt,"DB") || + !my_stricmp(current_line->opcode_txt,"ADR") || !my_stricmp(current_line->opcode_txt,"ADRL")) + { + /* Découpe en plusieurs éléments */ + tab_element = DecodeOperandeAsElementTable(current_line->operand_txt,&nb_element,SEPARATOR_DATA_VALUES,current_line); + if(tab_element == NULL) + { + sprintf(buffer_error_rtn,"Impossible to decode Operand '%s' as element table",current_line->operand_txt); + return; + } + + /** On va analyser les éléments **/ + for(i=0,nb_valid_element=0; ioperand_txt); + return; + } + else if(!strcmp(tab_element[i],",")) + ; /* On ne fait rien */ + else + nb_valid_element++; /* On ne comptabilise que les éléments valides */ + + /** Taille de la partie Data **/ + if(!my_stricmp(current_line->opcode_txt,"DA") || !my_stricmp(current_line->opcode_txt,"DW") || !my_stricmp(current_line->opcode_txt,"DDB")) + current_line->nb_byte = 2*nb_valid_element; + else if(!my_stricmp(current_line->opcode_txt,"DFB") || !my_stricmp(current_line->opcode_txt,"DB")) + current_line->nb_byte = nb_valid_element; + else if(!my_stricmp(current_line->opcode_txt,"ADR")) + current_line->nb_byte = 3*nb_valid_element; + else if(!my_stricmp(current_line->opcode_txt,"ADRL")) + current_line->nb_byte = 4*nb_valid_element; + + /* Libération mémoire */ + mem_free_table(nb_element,tab_element); + } + else if(!my_stricmp(current_line->opcode_txt,"HEX")) + { + /** Compte le nombre de caractère / valide les données **/ + for(i=0,nb_byte=0,nb_nibble=0; i<(int)strlen(current_line->operand_txt); i++) + { + if((current_line->operand_txt[i] >= '0' && current_line->operand_txt[i] <= '9') || (toupper(current_line->operand_txt[i]) >= 'A' && toupper(current_line->operand_txt[i]) <= 'F')) + { + nb_nibble++; + if(nb_nibble == 2) + { + nb_byte++; + nb_nibble = 0; + } + } + else if(current_line->operand_txt[i] == ',') + { + if(nb_nibble == 1) + { + sprintf(buffer_error_rtn,"Wrong Hex Format Data in Operand '%s'",current_line->operand_txt); + return; + } + } + else + { + sprintf(buffer_error_rtn,"Wrong Hex Format Data in Operand '%s'",current_line->operand_txt); + return; + } + } + if(nb_nibble == 1) + { + sprintf(buffer_error_rtn,"Wrong Hex Format Data in Operand '%s'",current_line->operand_txt); + return; + } + + /** Taille de la partie Data **/ + current_line->nb_byte = nb_byte; + } + else if(!my_stricmp(current_line->opcode_txt,"DS")) + { + /* Découpe en plusieurs éléments */ + tab_element = DecodeOperandeAsElementTable(current_line->operand_txt,&nb_element,SEPARATOR_DATA_VALUES,current_line); + if(tab_element == NULL) + { + sprintf(buffer_error_rtn,"Impossible to decode Operand '%s' as element table",current_line->operand_txt); + return; + } + /* DS 2 ou DS 2,FF */ + if(nb_element != 1 && nb_element != 3) + { + mem_free_table(nb_element,tab_element); + sprintf(buffer_error_rtn,"Wrong DS Format Data in Operand '%s'",current_line->operand_txt); + return; + } + + /** Cas particulier du \ **/; + if(!strcmp(tab_element[0],"\\")) + { + /** Taille de la partie Data => il faudra complèter jusqu'à la Page suivante **/ + current_line->nb_byte = 0xFFFF; /* 4 F */ + } + else + { + /* On évalue comme entier la première valeur */ + nb_byte = (int) EvalExpressionAsInteger(tab_element[0],buffer_error,current_line,1,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) > 0 && nb_byte == 0xFFFF) + { + /** Taille de la partie Data => il faudra refaire l'évaluation plus tard lors du calcul des adresses **/ + current_line->nb_byte = 0xFFFFF; /* 5 F */ + } + else if(strlen(buffer_error) > 0) + { + mem_free_table(nb_element,tab_element); + sprintf(buffer_error_rtn,"Wrong DS Format Data in Operand '%s' (%s)",current_line->operand_txt,buffer_error); + return; + } + else if(nb_byte < 0) + { + mem_free_table(nb_element,tab_element); + sprintf(buffer_error_rtn,"Wrong DS Value in Operand '%s' : Negative value (%d)",current_line->operand_txt,nb_byte); + return; + } + else + { + /** Taille de la partie Data **/ + current_line->nb_byte = nb_byte; + } + } + } + /**************************/ + /** Chaine de caractères **/ + /**************************/ + else if(!my_stricmp(current_line->opcode_txt,"ASC") || !my_stricmp(current_line->opcode_txt,"DCI") || !my_stricmp(current_line->opcode_txt,"INV") || !my_stricmp(current_line->opcode_txt,"FLS") || + !my_stricmp(current_line->opcode_txt,"STR") || !my_stricmp(current_line->opcode_txt,"STRL")) + { + /** Comptabilise les caractères dans les "" et les Hex à l'extérieur **/ + for(i=0,nb_nibble=0,nb_byte=0; i<(int)strlen(current_line->operand_txt); i++) + { + /* Début de zone */ + if(current_line->operand_txt[i] == '\'' || current_line->operand_txt[i] == '"') + { + /* Hexa précédent non terminé */ + if(nb_nibble == 1) + { + sprintf(buffer_error_rtn,"Wrong Data String format in Operand '%s'",current_line->operand_txt); + return; + } + + /* Fin de zone */ + next_char = strchr(¤t_line->operand_txt[i+1],current_line->operand_txt[i]); + if(next_char == NULL) + { + sprintf(buffer_error_rtn,"Wrong String Format Data in Operand '%s' : End-of-String character is missing",current_line->operand_txt); + return; + } + + /* Taille de la zone */ + length = (int) ((next_char - ¤t_line->operand_txt[i]) - 1); + nb_byte += length; + + /* On continue */ + i += (length+1); + continue; + } + else if(current_line->operand_txt[i] == ',') + { + if(nb_nibble == 1) + { + sprintf(buffer_error_rtn,"Wrong Data String format in Operand '%s'",current_line->operand_txt); + return; + } + } + else if((current_line->operand_txt[i] >= '0' && current_line->operand_txt[i] <= '9') || (toupper(current_line->operand_txt[i]) >= 'A' && toupper(current_line->operand_txt[i]) <= 'F')) + { + nb_nibble++; + if(nb_nibble == 2) + { + nb_byte++; + nb_nibble = 0; + } + } + } + if(nb_nibble == 1) + { + sprintf(buffer_error_rtn,"Wrong Data String format in Operand '%s'",current_line->operand_txt); + return; + } + + /** Taille de la partie Data **/ + if(!my_stricmp(current_line->opcode_txt,"STR")) + { + if(nb_byte > 255) + { + sprintf(buffer_error_rtn,"STR String is too long in Operand '%s'",current_line->operand_txt); + return; + } + current_line->nb_byte = 1 + nb_byte; + } + else if(!my_stricmp(current_line->opcode_txt,"STRL")) + current_line->nb_byte = 2 + nb_byte; + else + current_line->nb_byte = nb_byte; + } + else if(!my_stricmp(current_line->opcode_txt,"REV")) + { + /** Pas de Hex dans la chaine **/ + /* Début de zone */ + if(current_line->operand_txt[0] != '\'' && current_line->operand_txt[0] != '"') + { + sprintf(buffer_error_rtn,"Wrong Data String format in Operand '%s'",current_line->operand_txt); + return; + } + /* Fin de zone */ + if(current_line->operand_txt[strlen(current_line->operand_txt)-1] != current_line->operand_txt[0]) + { + sprintf(buffer_error_rtn,"Wrong Data String format in Operand '%s'",current_line->operand_txt); + return; + } + + /** Taille de la partie Data **/ + current_line->nb_byte = (int) (strlen(current_line->operand_txt) - 2); + } + else if(!my_stricmp(current_line->opcode_txt,"CHK")) + { + /* 1 Byte de Checksum */ + current_line->nb_byte = 1; + } + else + { + /* Data inconnu */ + sprintf(param->buffer_error,"Impossible to decode Data mode for instruction '%s %s' (line %d, file '%s')", + current_line->opcode_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } +} + + +/************************************************************************************************/ +/* BuildOneDataLineOperand() : Création des octets de la partie Operand pour les lignes Data. */ +/************************************************************************************************/ +static void BuildOneDataLineOperand(struct source_line *current_line, char *buffer_error_rtn, struct omf_segment *current_omfsegment) +{ + BYTE one_byte, byte_count, bit_shift; + WORD one_word, offset_patch, offset_reference; + DWORD one_dword, address_long; + int i, j, nb_element, nb_valid_element, nb_byte, nb_nibble, length, value, is_reloc, operand_size, line_address; + struct relocate_address *current_address_1; + struct relocate_address *current_address_2; + struct external *current_external; + char *next_char; + char **tab_element; + unsigned char data[5]; + char buffer_error[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + strcpy(buffer_error_rtn,""); + + /*** On va reconnaitre les différents types de Data ***/ + if(!my_stricmp(current_line->opcode_txt,"DA") || !my_stricmp(current_line->opcode_txt,"DW") || !my_stricmp(current_line->opcode_txt,"DDB") || + !my_stricmp(current_line->opcode_txt,"DFB") || !my_stricmp(current_line->opcode_txt,"DB") || + !my_stricmp(current_line->opcode_txt,"ADR") || !my_stricmp(current_line->opcode_txt,"ADRL")) + { + /** Taille de l'Operand **/ + if(!my_stricmp(current_line->opcode_txt,"DFB") || !my_stricmp(current_line->opcode_txt,"DB")) + operand_size = 1; + else if(!my_stricmp(current_line->opcode_txt,"DA") || !my_stricmp(current_line->opcode_txt,"DW") || !my_stricmp(current_line->opcode_txt,"DDB")) + operand_size = 2; + else if(!my_stricmp(current_line->opcode_txt,"ADR")) + operand_size = 3; + else if(!my_stricmp(current_line->opcode_txt,"ADRL")) + operand_size = 4; + + /* Découpe en plusieurs éléments */ + tab_element = DecodeOperandeAsElementTable(current_line->operand_txt,&nb_element,SEPARATOR_DATA_VALUES,current_line); + if(tab_element == NULL) + { + sprintf(buffer_error_rtn,"Impossible to decode Operand '%s' as element table",current_line->operand_txt); + return; + } + + /** On convertir les valeurs **/ + for(i=0,nb_valid_element=0; i 0) + { + sprintf(buffer_error_rtn,"Impossible to evaluate %s Data '%s' (%s)",current_line->opcode_txt,tab_element[i],buffer_error); + mem_free_table(nb_element,tab_element); + return; + } + + /* L'adresse de la ligne tient compte des [ORG $Addr ORG] */ + if(current_line->is_fix_address == 1 && current_line->address != current_line->global_address) + line_address = current_line->global_address; + else + line_address = current_line->address; + + /** Découpage en Byte (copie respectant le Byte Order) **/ + bo_memcpy(&data[0],&one_dword,sizeof(DWORD)); + + /** Stockage dans L'opérande **/ + if(!my_stricmp(current_line->opcode_txt,"DA") || !my_stricmp(current_line->opcode_txt,"DW")) + { + current_line->data[2*nb_valid_element+0] = data[0]; + current_line->data[2*nb_valid_element+1] = data[1]; + + /* Adresse Relogeable */ + offset_patch = line_address + 2*nb_valid_element + 0; /* 2 Bytes */ + } + else if(!my_stricmp(current_line->opcode_txt,"DDB")) + { + current_line->data[2*nb_valid_element+0] = data[1]; + current_line->data[2*nb_valid_element+1] = data[0]; + + /* Adresse Relogeable */ + offset_patch = line_address + 2*nb_valid_element + 0; /* 2 Bytes */ + } + else if(!my_stricmp(current_line->opcode_txt,"DFB") || !my_stricmp(current_line->opcode_txt,"DB")) + { + current_line->data[nb_valid_element] = data[0]; + + /* Adresse Relogeable */ + offset_patch = line_address + nb_valid_element + 0; /* 1 Byte */ + } + else if(!my_stricmp(current_line->opcode_txt,"ADR")) + { + current_line->data[3*nb_valid_element+0] = data[0]; + current_line->data[3*nb_valid_element+1] = data[1]; + current_line->data[3*nb_valid_element+2] = data[2]; + + /* Adresse Relogeable */ + offset_patch = line_address + 3*nb_valid_element + 0; /* 3 Bytes */ + } + else if(!my_stricmp(current_line->opcode_txt,"ADRL")) + { + current_line->data[4*nb_valid_element+0] = data[0]; + current_line->data[4*nb_valid_element+1] = data[1]; + current_line->data[4*nb_valid_element+2] = data[2]; + current_line->data[4*nb_valid_element+3] = data[3]; + + /* Adresse Relogeable */ + offset_patch = line_address + 4*nb_valid_element + 0; /* 4 Bytes */ + } + + /** Adresse Relogeable (interne ou externe au Segment) **/ + if(is_reloc) + { + /* Cas particulier du DDB qui reloge 2 adresses sur 1 byte, plutot qu'une adresse sur 2 bytes ! */ + if(!my_stricmp(current_line->opcode_txt,"DDB")) + { + /* Adresse 1 : >> 8 */ + current_address_1 = BuildRelocateAddress(1,0xF8,offset_patch,offset_reference,current_external,current_omfsegment); + current_address_1->object_line = ¤t_line->data[2*nb_valid_element+0]; + + /* Adresse 2 */ + current_address_2 = BuildRelocateAddress(1,0,offset_patch+1,offset_reference,current_external,current_omfsegment); + current_address_2->object_line = ¤t_line->data[2*nb_valid_element+1]; + + /* Information pour le fichier Output.txt (on n'indique qu'un seul relogeage) */ + sprintf(current_line->reloc,"%c 1 >> 8 ",(current_external == NULL)?' ':'E'); + } + else + { + /* 1 seule adresse à reloger */ + current_address_1 = BuildRelocateAddress(byte_count,bit_shift,offset_patch,offset_reference,current_external,current_omfsegment); + + /* Adresse à pacther dans la line */ + if(!my_stricmp(current_line->opcode_txt,"DFB") || !my_stricmp(current_line->opcode_txt,"DB")) + current_address_1->object_line = ¤t_line->data[1*nb_valid_element+0]; /* 1 byte */ + else if(!my_stricmp(current_line->opcode_txt,"DA") || !my_stricmp(current_line->opcode_txt,"DW")) + current_address_1->object_line = ¤t_line->data[2*nb_valid_element+0]; /* 2 bytes */ + else if(!my_stricmp(current_line->opcode_txt,"ADR")) + current_address_1->object_line = ¤t_line->data[3*nb_valid_element+0]; /* 3 bytes */ + else if(!my_stricmp(current_line->opcode_txt,"ADRL")) + current_address_1->object_line = ¤t_line->data[4*nb_valid_element+0]; /* 4 bytes */ + + /* Version Texte pour le Output.txt */ + sprintf(current_line->reloc,"%c %d",(current_external == NULL)?' ':'E',byte_count); + if(bit_shift == 0xF0) + strcat(current_line->reloc," >>16 "); + else if(bit_shift == 0xF8) + strcat(current_line->reloc," >> 8 "); + else + strcat(current_line->reloc," "); + } + } + + /* Element suivant */ + nb_valid_element++; + } + } + + /* Libération mémoire */ + mem_free_table(nb_element,tab_element); + } + else if(!my_stricmp(current_line->opcode_txt,"HEX")) + { + /** Conversion de l'Hexadécimal **/ + for(i=0,nb_byte=0,nb_nibble=0; i<(int)strlen(current_line->operand_txt); i++) + { + if((current_line->operand_txt[i] >= '0' && current_line->operand_txt[i] <= '9') || (toupper(current_line->operand_txt[i]) >= 'A' && toupper(current_line->operand_txt[i]) <= 'F')) + { + nb_nibble++; + if(nb_nibble == 2) + { + data[1] = current_line->operand_txt[i]; + data[2] = '\0'; + sscanf((char *)data,"%X",&value); + current_line->data[nb_byte++] = (unsigned char) value; + nb_nibble = 0; + } + else + data[0] = current_line->operand_txt[i]; + } + } + } + else if(!my_stricmp(current_line->opcode_txt,"DS")) + { + /* Découpe en plusieurs éléments */ + tab_element = DecodeOperandeAsElementTable(current_line->operand_txt,&nb_element,SEPARATOR_DATA_VALUES,current_line); + if(tab_element == NULL) + { + sprintf(buffer_error_rtn,"Impossible to decode Operand '%s' as element table",current_line->operand_txt); + return; + } + + /** On vérifie si le remplissage se fait avec une valeur particulière **/ + if(nb_element == 3) + { + /* On évalue comme entier la deuxième valeur */ + one_dword = (DWORD) EvalExpressionAsInteger(tab_element[2],buffer_error,current_line,1,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(buffer_error_rtn,"Impossible to evaluate DS Data '%s' in Operand '%s' (%s)",tab_element[2],current_line->operand_txt,buffer_error); + mem_free_table(nb_element,tab_element); + return; + } + + /** Découpage en Byte (copie respectant le Byte Order) **/ + bo_memcpy(&data[0],&one_dword,sizeof(DWORD)); + + /** On remplit les Data **/ + for(i=0; inb_byte; i++) + current_line->data[i] = data[0]; + } + } + /**************************/ + /** Chaine de caractères **/ + /**************************/ + else if(!my_stricmp(current_line->opcode_txt,"ASC") || !my_stricmp(current_line->opcode_txt,"DCI") || !my_stricmp(current_line->opcode_txt,"INV") || !my_stricmp(current_line->opcode_txt,"FLS") || + !my_stricmp(current_line->opcode_txt,"STR") || !my_stricmp(current_line->opcode_txt,"STRL")) + { + /** Extraction de la chaine de caractère en indiquant où sont les parties Hexa **/ + for(i=0,nb_nibble=0,nb_byte=0; i<(int)strlen(current_line->operand_txt); i++) + { + /* Début de zone */ + if(current_line->operand_txt[i] == '\'' || current_line->operand_txt[i] == '"') + { + /* Fin de zone */ + next_char = strchr(¤t_line->operand_txt[i+1],current_line->operand_txt[i]); + + /* Taille de la zone */ + length = (int) ((next_char - ¤t_line->operand_txt[i]) - 1); + for(j=0; jopcode_txt,"INV") || !my_stricmp(current_line->opcode_txt,"FLS")) + next_char = (char *) strchr(INVFLS_TABLE,current_line->operand_txt[i+1+j]); + else + next_char = (char *) strchr(ASCII_TABLE,current_line->operand_txt[i+1+j]); + if(next_char == NULL) + { + sprintf(buffer_error_rtn,"The character '%c' is not valid with Directive %s",current_line->operand_txt[i+1+j],current_line->opcode_txt); + return; + } + + /* Ajuste le bit 7 */ + if(current_line->operand_txt[i] == '"') + param->buffer_string[nb_byte+j] = (0x80 | current_line->operand_txt[i+1+j]); + else + param->buffer_string[nb_byte+j] = (0x7F & current_line->operand_txt[i+1+j]); + } + + /* Conserve le rang */ + nb_byte += length; + + /* On continue */ + i += (length+1); + continue; + } + else if((current_line->operand_txt[i] >= '0' && current_line->operand_txt[i] <= '9') || (toupper(current_line->operand_txt[i]) >= 'A' && toupper(current_line->operand_txt[i]) <= 'F')) + { + nb_nibble++; + if(nb_nibble == 2) + { + /* Récupération du Byte */ + data[1] = current_line->operand_txt[i]; + data[2] = '\0'; + sscanf((char *)data,"%X",&value); + + /* Conserve le caractère */ + param->buffer_string[nb_byte] = (unsigned char) value; + nb_byte++; + nb_nibble = 0; + } + else + data[0] = current_line->operand_txt[i]; + } + } + + /** Stockage de la chaine en fonction de l'Opcode **/ + if(!my_stricmp(current_line->opcode_txt,"ASC")) + { + /* Conserve la chaine telle qu'elle */ + memcpy(current_line->data,param->buffer_string,nb_byte); + } + else if(!my_stricmp(current_line->opcode_txt,"DCI")) + { + memcpy(current_line->data,param->buffer_string,nb_byte); + if((current_line->data[nb_byte-1] & 0x80) == 0x00) + current_line->data[nb_byte-1] = (0x80 | current_line->data[nb_byte-1]); + else + current_line->data[nb_byte-1] = (0x7F & current_line->data[nb_byte-1]); + } + else if(!my_stricmp(current_line->opcode_txt,"INV")) + { + /* On va passer en codage 0x00-0x3F */ + for(i=0; idata[i] = (param->buffer_string[i] & 0x3F); + } + else if(!my_stricmp(current_line->opcode_txt,"FLS")) + { + /* On va passer en codage 0x40-0x7F */ + for(i=0; idata[i] = (param->buffer_string[i] & 0x7F); + } + else if(!my_stricmp(current_line->opcode_txt,"STR")) + { + one_byte = (BYTE) nb_byte; + bo_memcpy(¤t_line->data[0],&one_byte,1); /* Byte Order */ + memcpy(¤t_line->data[1],param->buffer_string,nb_byte); + } + else if(!my_stricmp(current_line->opcode_txt,"STRL")) + { + one_word = (WORD) nb_byte; + bo_memcpy(¤t_line->data[0],&one_word,2); /* Byte Order */ + memcpy(¤t_line->data[2],param->buffer_string,nb_byte); + } + } + else if(!my_stricmp(current_line->opcode_txt,"REV")) + { + /** Pas de Hex dans la chaine **/ + for(i=0; inb_byte; i++) + { + if(current_line->operand_txt[0] == '"') + current_line->data[i] = (0x80 | current_line->operand_txt[current_line->nb_byte-i]); + else + current_line->data[i] = (0x7F & current_line->operand_txt[current_line->nb_byte-i]); + } + } + else if(!my_stricmp(current_line->opcode_txt,"CHK")) + { + /* 1 Byte de Checksum : On met un 0x00 pour l'instant */ + current_line->data[0] = 0x00; + } +} + +/***********************************************************************/ diff --git a/Source/a65816_Data.h b/Source/a65816_Data.h new file mode 100644 index 0000000..2deee61 --- /dev/null +++ b/Source/a65816_Data.h @@ -0,0 +1,12 @@ +/***********************************************************************/ +/* */ +/* a65816_Data.h : Header pour la génération des Data. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +int BuildAllDataLineSize(struct omf_segment *); +int BuildAllDataLine(struct omf_segment *); + +/***********************************************************************/ diff --git a/Source/a65816_File.c b/Source/a65816_File.c new file mode 100644 index 0000000..e69d886 --- /dev/null +++ b/Source/a65816_File.c @@ -0,0 +1,885 @@ +/***********************************************************************/ +/* */ +/* a65816_File.c : Module pour la gestion des fichiers. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +#include +#include +#include +#include + +#include "Dc_Library.h" +#include "a65816_Line.h" +#include "a65816_Macro.h" +#include "a65816_OMF.h" +#include "a65816_File.h" + + +/*******************************************************************/ +/* LoadAllSourceFile() : Chargement de tous les fichiers Source. */ +/*******************************************************************/ +int LoadAllSourceFile(char *first_file_path, char *macro_folder_path, struct omf_segment *current_omfsegment) +{ + int i, file_number, line_number, nb_error; + struct source_file *first_file; + struct source_file *last_file; + struct source_file *new_file; + struct source_line *current_line; + struct source_line *next_line; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + file_number = 1; + nb_error = 0; + + /* Extrait le nom du fichier */ + for(i=(int)strlen(first_file_path); i>=0; i--) + if(first_file_path[i] == '/' || first_file_path[i] == '\\') + break; + strcpy(param->buffer_file_name,&first_file_path[i+1]); + + /** Chargement du premier fichier Source **/ + printf(" - %s\n",param->buffer_file_name); + first_file = LoadOneSourceFile(first_file_path,param->buffer_file_name,file_number); + if(first_file == NULL) + { + sprintf(param->buffer_error,"Impossible to load Source file '%s'",first_file_path); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + last_file = first_file; + + /* Stocke le premier fichier Source */ + my_Memory(MEMORY_SET_FILE,first_file,NULL,current_omfsegment); + + /** Chargement de tous les fichiers Source : On ne regarde que dans le 1er fichier **/ + for(current_line = first_file->first_line; current_line; ) + { + if((!my_stricmp(current_line->opcode_txt,"PUT") || !my_stricmp(current_line->opcode_txt,"PUTBIN") || !my_stricmp(current_line->opcode_txt,"USE")) && strlen(current_line->operand_txt) > 0) + { + /* Si l'inclusion se fait par un Use on vérifie si on a affaire à un fichier de Macro */ + if(!my_stricmp(current_line->opcode_txt,"USE") && IsMacroFile(current_line->operand_txt,param->source_folder_path,macro_folder_path)) + { + current_line = current_line->next; + continue; + } + + /* Nouveau fichier */ + file_number++; + + /* On insère le nouveau fichier ici */ + next_line = current_line->next; + + /** Fichier Source ou Macro **/ + if(!my_stricmp(current_line->opcode_txt,"PUT") || !my_stricmp(current_line->opcode_txt,"USE")) + { + /* Construit le nom du fichier */ + strcpy(param->buffer_file_name,current_line->operand_txt); + + /* Construit le chemin complet du fichier */ + sprintf(param->buffer_file_path,"%s%s",param->source_folder_path,param->buffer_file_name); + + /* Faut t'il ajouter un .s ? */ + if(my_IsFileExist(param->buffer_file_path) == 0) + { + /* Le fichier n'existe pas */ + if(strlen(param->buffer_file_name) > 2) + if(my_stricmp(¶m->buffer_file_name[strlen(param->buffer_file_name)-2],".s")) + { + /* Ajoute le .s au nom et au chemin complet */ + strcat(param->buffer_file_name,".s"); + strcat(param->buffer_file_path,".s"); + } + } + + /* Charge le fichier Texte */ + printf(" - %s\n",param->buffer_file_name); + new_file = LoadOneSourceFile(param->buffer_file_path,param->buffer_file_name,file_number); + if(new_file == NULL) + { + sprintf(param->buffer_error,"Impossible to open Source file '%s'",param->buffer_file_path); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + } + else /* PUTBIN : Fichier Binaire */ + { + /* Construit le nom */ + strcpy(param->buffer_file_name,current_line->operand_txt); + + /* Construit le chemin */ + sprintf(param->buffer_file_path,"%s%s",param->source_folder_path,param->buffer_file_name); + + /* Charge le fichier Binaire */ + printf(" - %s\n",param->buffer_file_name); + new_file = LoadOneBinaryFile(param->buffer_file_path,param->buffer_file_name,file_number); + if(new_file == NULL) + { + sprintf(param->buffer_error,"Impossible to open Binary file '%s'",param->buffer_file_path); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + } + + /* Attache ce fichier aux précédents */ + if(new_file != NULL) + { + last_file->next = new_file; + last_file = new_file; + } + + /* Insère les lignes de ce fichier aux lignes précédantes */ + if(new_file != NULL) + { + new_file->last_line->next = current_line->next; + current_line->next = new_file->first_line; + } + + /* Ligne suivante */ + current_line = next_line; + } + else + current_line = current_line->next; + } + + /** Numérotation globale des lignes **/ + for(line_number=1,current_line = first_file->first_line; current_line; current_line = current_line->next,line_number++) + current_line->line_number = line_number; + + /* OK */ + return(nb_error); +} + + +/***********************************************************/ +/* LoadOneSourceFile() : Chargement d'un fichier Source. */ +/***********************************************************/ +struct source_file *LoadOneSourceFile(char *file_path, char *file_name, int file_number) +{ + struct source_file *current_file; + struct source_line *current_line; + int i, file_size, nb_line; + unsigned char *file_data; + char *begin_line; + char *end_line; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Chargement du fichier */ + file_data = LoadTextFileData(file_path,&file_size); + if(file_data == NULL) + return(NULL); + + /* Allocation mémoire */ + current_file = (struct source_file *) calloc(1,sizeof(struct source_file)); + if(current_file == NULL) + { + free(file_data); + return(NULL); + } + + /* Data */ + current_file->data = file_data; + + /* File Path */ + current_file->file_path = strdup(file_path); + + /* Build file name */ + current_file->file_name = strdup(file_name); + + /* File number */ + current_file->file_number = file_number; + + /* Compte le nombre de lignes */ + for(i=0,nb_line=1; idata[i] == '\n') + nb_line++; + + /* Allocation mémoire du tableau de ligne */ + current_file->tab_line = (char **) calloc(nb_line,sizeof(char *)); + + /* Vérification des allocations mémoires */ + if(current_file->file_path == NULL || current_file->file_name == NULL || current_file->tab_line == NULL) + { + mem_free_sourcefile(current_file,0); + return(NULL); + } + + /** Détermine le début de chaque ligne **/ + begin_line = (char *) current_file->data; + for(i=0; begin_line; i++) + { + /* Conserve un pointeur sur le début de ligne */ + current_file->tab_line[i] = begin_line; + + /* Fin de ligne */ + end_line = strchr(begin_line,'\n'); + if(end_line != NULL) + *end_line = '\0'; + + /* Ligne suivante */ + begin_line = (end_line == NULL) ? NULL : end_line+1; + } + current_file->nb_line = i; + + /** Création des lignes **/ + for(i=0; inb_line; i++) + { + /* Décodage de la ligne */ + current_line = BuildSourceLine(current_file,i); + if(current_line == NULL) + { + mem_free_sourcefile(current_file,0); + sprintf(param->buffer_error,"Impossible to build source line %d",i); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Si on tomber sur un END, on s'arrête là */ + if(!my_stricmp(current_line->opcode_txt,"END")) + { + current_file->nb_line = i+1; + break; + } + + /* On va repérer les lignes utilisant déjà un label ozunid_ */ + if(!my_strnicmp(current_line->label_txt,"ozunid_",strlen("ozunid_"))) + ProcessOZUNIDLine(current_line->label_txt); + + /* Attachement à la liste */ + if(current_file->first_line == NULL) + current_file->first_line = current_line; + else + current_file->last_line->next = current_line; + current_file->last_line = current_line; + } + + /* Renvoi la structure */ + return(current_file); +} + + +/***********************************************************/ +/* LoadOneBinaryFile() : Chargement d'un fichier Source. */ +/***********************************************************/ +struct source_file *LoadOneBinaryFile(char *file_path, char *file_name, int file_number) +{ + struct source_file *current_file; + struct source_line *current_line; + int i, offset, file_bin_size, file_size, nb_line; + char *file_data; + unsigned char *file_bin_data; + char *begin_line; + char *end_line; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Chargement du fichier Bin */ + file_bin_data = LoadBinaryFileData(file_path,&file_bin_size); + if(file_bin_data == NULL) + return(NULL); + + /** Converion en buffer Texte avec des HEX byte,byte... **/ + nb_line = file_bin_size / 16; + if(nb_line*16 != file_bin_size) + nb_line++; /* La dernière ligne n'aura pas 16 bytes de Data */ + file_size = nb_line*((int)strlen(" HEX \n")) + file_bin_size*3 + 1; /* 0A, */ + + /* Allocation mémoire */ + file_data = (char *) calloc(file_size,sizeof(char)); + if(file_data == NULL) + { + free(file_bin_data); + return(NULL); + } + + /* Construction du buffer Texte */ + for(i=0,offset=0; i 0) + { + strcpy(&file_data[offset],"\n"); + offset++; + } + /* Début de ligne */ + strcpy(&file_data[offset]," HEX "); + offset += (int) strlen(" HEX "); + } + + /* On place une valeur */ + sprintf(&file_data[offset],"%02X",file_bin_data[i]); + offset += 2; + + /* On ajoute la , */ + if(i%16 != 15 && i != (file_bin_size-1)) + { + strcpy(&file_data[offset],","); + offset++; + } + } + /* Fin de la dernière ligne */ + strcat(file_data,"\n"); + file_size = (int) strlen(file_data); + + /* Libération mémoire du fichier Binaire */ + free(file_bin_data); + + /* Allocation mémoire */ + current_file = (struct source_file *) calloc(1,sizeof(struct source_file)); + if(current_file == NULL) + { + free(file_data); + return(NULL); + } + + /* Data */ + current_file->data = (unsigned char *) file_data; + + /* File Path */ + current_file->file_path = strdup(file_path); + + /* Build file name */ + current_file->file_name = strdup(file_name); + + /* File number */ + current_file->file_number = file_number; + + /* Compte le nombre de lignes */ + for(i=0,nb_line=1; idata[i] == '\n') + nb_line++; + + /* Allocation mémoire du tableau de ligne */ + current_file->tab_line = (char **) calloc(nb_line,sizeof(char *)); + + /* Vérification des allocations mémoires */ + if(current_file->file_path == NULL || current_file->file_name == NULL || current_file->tab_line == NULL) + { + mem_free_sourcefile(current_file,0); + return(NULL); + } + + /** Détermine le début de chaque ligne **/ + begin_line = (char *) current_file->data; + for(i=0; begin_line; i++) + { + /* Conserve un pointeur sur le début de ligne */ + current_file->tab_line[i] = begin_line; + + /* Fin de ligne */ + end_line = strchr(begin_line,'\n'); + if(end_line != NULL) + *end_line = '\0'; + + /* Ligne suivante */ + begin_line = (end_line == NULL) ? NULL : end_line+1; + } + current_file->nb_line = i; + + /** Création des lignes **/ + for(i=0; inb_line; i++) + { + /* Décodage de la ligne */ + current_line = BuildSourceLine(current_file,i); + if(current_line == NULL) + { + mem_free_sourcefile(current_file,0); + sprintf(param->buffer_error,"Impossible to build source line %d",i); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Attachement à la liste */ + if(current_file->first_line == NULL) + current_file->first_line = current_line; + else + current_file->last_line->next = current_line; + current_file->last_line = current_line; + } + + /* Renvoi la structure */ + return(current_file); +} + + +/****************************************************/ +/* BuildObjectCode() : Création du fichier Objet. */ +/****************************************************/ +int BuildObjectCode(struct omf_segment *current_omfsegment) +{ + BYTE checksum_byte; + int i, object_length; + struct source_file *first_file; + struct source_line *current_line; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /** Calcul la taille max de l'object **/ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + for(object_length=0,current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ne prend pas les lignes invalides */ + if(current_line->is_valid == 0 || current_line->is_dum == 1) + continue; + + /* Pour une Macro, on ne prend que la ligne d'appel */ + if(current_line->type == LINE_MACRO && current_line->is_in_source == 0) + continue; + if(current_line->type == LINE_DIRECTIVE && current_line->is_in_source == 0) + continue; + + /* Comptabilise la taille du code objet */ + object_length += current_line->nb_byte; + } + + /* Allocation mémoire */ + current_omfsegment->object_code = (unsigned char *) calloc(object_length+1,sizeof(unsigned char)); + if(current_omfsegment->object_code == NULL) + return(1); + + /** Remplissage du buffer objet **/ + for(object_length=0,current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ne prend pas les lignes invalides */ + if(current_line->is_valid == 0 || current_line->is_dum == 1) + continue; + + /* Pour une Macro, on ne prend que la ligne d'appel */ + if(current_line->type == LINE_MACRO && current_line->is_in_source == 0) + continue; + if(current_line->type == LINE_DIRECTIVE && current_line->is_in_source == 0) + continue; + if(current_line->nb_byte == 0) /* ERR */ + continue; + + /** Place le code objet **/ + if(current_line->type == LINE_CODE) + { + /* Opcode Byte + Operand Byte(s) */ + current_omfsegment->object_code[object_length++] = current_line->opcode_byte; + memcpy(¤t_omfsegment->object_code[object_length],current_line->operand_byte,current_line->nb_byte-1); + object_length += current_line->nb_byte-1; + } + else if(current_line->type == LINE_DATA && !my_stricmp(current_line->opcode_txt,"CHK")) + { + /* Calcule le checksum depuis le début */ + for(i=0; iobject_code[i] : (checksum_byte ^ current_omfsegment->object_code[i]); + + /* Checksum Byte */ + current_omfsegment->object_code[object_length] = checksum_byte; + object_length++; + } + else if(current_line->type == LINE_DATA) + { + /* Data Byte(s) */ + memcpy(¤t_omfsegment->object_code[object_length],current_line->data,current_line->nb_byte); + object_length += current_line->nb_byte; + } + } + + /* Taille du code objet */ + current_omfsegment->object_length = object_length; + + /* OK */ + return(0); +} + + +/***************************************************************/ +/* BuildObjectFile() : Création du fichier Objet sur disque. */ +/***************************************************************/ +int BuildObjectFile(char *output_folder_path, struct omf_segment *current_omfsegment, struct omf_project *current_omfproject) +{ + FILE *fd; + int i, nb_write; + char file_path[1024]; + struct source_file *first_file; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Récupère le premier fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /** A t'on précisé un nom de sortie ? **/ + if(strlen(current_omfsegment->object_name) == 0) + { + /* On utilise le nom du fichier Source */ + strcpy(current_omfsegment->object_name,first_file->file_name); + for(i=(int)strlen(current_omfsegment->object_name); i>=0; i--) + if(current_omfsegment->object_name[i] == '.') + { + current_omfsegment->object_name[i] = '\0'; + break; + } + } + + /** A t'on un nom pour le fichier Output.txt ? **/ + if(current_omfproject->nb_segment == 1) + { + if(strlen(param->output_file_path) == 0 || !my_stricmp(param->output_file_path,param->current_folder_path)) + sprintf(param->output_file_path,"%s%s_Output.txt",param->current_folder_path,current_omfsegment->object_name); + } + else + { + if(strlen(param->output_file_path) == 0 || !my_stricmp(param->output_file_path,param->current_folder_path)) + sprintf(param->output_file_path,"%s%s_S%02X_Output.txt",param->current_folder_path,current_omfsegment->object_name,current_omfsegment->segment_number); /* Multi Segments */ + } + + /*** Création du fichier sur le disque ***/ + sprintf(file_path,"%s%s",output_folder_path,current_omfsegment->object_name); + + /* Information */ + printf(" => Creating Object file '%s'\n",file_path); + + /* Création du fichier */ +#if defined(WIN32) || defined(WIN64) + fd = fopen(file_path,"wb+"); +#else + fd = fopen(file_path,"w+"); +#endif + if(fd == NULL) + { + printf(" Error : Can't create Object file '%s'.\n",file_path); + return(1); + } + + /* Ecriture du Body dans le fichier */ + nb_write = (int) fwrite(current_omfsegment->object_code,1,current_omfsegment->object_length,fd); + if(nb_write != current_omfsegment->object_length) + printf(" Error : Can't write Object file '%s' data (%d bytes / %d bytes).\n",file_path,nb_write,current_omfsegment->object_length); + + /* Fermeture du fichier */ + fclose(fd); + + /*** Mise à jour du fichier FileInformation ***/ + UpdateFileInformation(output_folder_path,current_omfsegment->object_name,current_omfproject); + + /* OK */ + return(0); +} + + +/*************************************************************************************************/ +/* BuildSingleObjectFile() : Création du fichier Objet Multi-Segment Single Binary sur disque. */ +/*************************************************************************************************/ +int BuildSingleObjectFile(char *output_folder_path, int file_number, struct omf_project *current_omfproject) +{ + FILE *fd; + int nb_write; + char file_path[1024]; + struct omf_segment *current_omfsegment; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /** A t'on un nom pour le fichier Output.txt ? **/ + if(strlen(param->output_file_path) == 0 || !my_stricmp(param->output_file_path,param->current_folder_path)) + sprintf(param->output_file_path,"%s%s_Output.txt",param->current_folder_path,current_omfproject->dsk_name_tab[file_number]); + + /*** Création du fichier sur le disque ***/ + sprintf(file_path,"%s%s",output_folder_path,current_omfproject->dsk_name_tab[file_number]); + + /* Information */ + printf(" => Creating Object file '%s'\n",file_path); + + /* Création du fichier */ +#if defined(WIN32) || defined(WIN64) + fd = fopen(file_path,"wb+"); +#else + fd = fopen(file_path,"w+"); +#endif + if(fd == NULL) + { + printf(" Error : Can't create Object file '%s'.\n",file_path); + return(1); + } + + /** Ecriture des Body dans le fichier les uns derrière les autres **/ + for(current_omfsegment=current_omfproject->first_segment; current_omfsegment; current_omfsegment=current_omfsegment->next) + { + /* 1 Segment (seulement s'il appartient au fichier) */ + if(current_omfsegment->file_number == (file_number+1)) + { + nb_write = (int) fwrite(current_omfsegment->object_code,1,current_omfsegment->object_length,fd); + if(nb_write != current_omfsegment->object_length) + { + printf(" Error : Can't write Object file '%s' data (%d bytes / %d bytes).\n",file_path,nb_write,current_omfsegment->object_length); + break; + } + } + } + + /* Fermeture du fichier */ + fclose(fd); + + /*** Mise à jour du fichier _FileInformation ***/ + UpdateFileInformation(output_folder_path,current_omfproject->dsk_name_tab[file_number],current_omfproject); + + /* OK */ + return(0); +} + + +/***************************************************************/ +/* CreateOutputFile() : Création du fichier de sortie Texte. */ +/***************************************************************/ +int CreateOutputFile(char *file_path, struct omf_segment *current_omfsegment, struct omf_project *current_omfproject) +{ + FILE *fd; + int i, j, nb_byte_left, is_multi_fixed, nb_byte; + int file_length; + int label_length; + int opcode_length; + int operand_length; + char buffer_format[256]; + struct source_file *first_file; + struct source_file *current_file; + struct source_line *current_line; + char *line_type_tab[] = {"Unknown ", "Comment ", "Directive ", "Equivalence", "Variable ", "Code ", "Data ", "Macro ", "Empty ", "Global ", "External "}; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + is_multi_fixed = 0; + + /* Est-ce un projet multi-segment fixed */ + if(current_omfproject != NULL) + if(current_omfproject->is_multi_fixed == 1) + is_multi_fixed = 1; + + /* Taille des noms de fichiers */ + file_length = 0; + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + if(first_file == NULL) + return(1); + for(current_file=first_file; current_file; current_file=current_file->next) + if(file_length < (int) strlen(current_file->file_name)) + file_length = (int) strlen(current_file->file_name); + if(file_length < 4) + file_length = 4; + + /* Information */ + printf(" => Creating Output file '%s'\n",file_path); + + /* Création du fichier de sortie */ + fd = fopen(file_path,"w+"); + if(fd == NULL) + return(1); + + /** Taille des marges **/ + label_length = 10; + opcode_length = 4; + operand_length = 15; + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ne prend pas les lignes invalides */ + if(current_line->is_valid == 0) + continue; + + /* Pour une Macro, on ne prend que la ligne d'appel */ + if(current_line->type == LINE_MACRO && current_line->is_in_source == 0) + continue; + if(current_line->type == LINE_DIRECTIVE && current_line->is_in_source == 0) + continue; + + /* On aligne la colonne du label sur le plus large */ + if((int) strlen(current_line->label_txt) > label_length) + label_length = (int) strlen(current_line->label_txt); + + /* On va regarde les opcode ayant un operand */ + if((int) strlen(current_line->opcode_txt) > opcode_length && (int) strlen(current_line->operand_txt) > 0) + opcode_length = (int) strlen(current_line->opcode_txt); + + /* On va regarder les operand ayant un commentaire */ + if((int) strlen(current_line->operand_txt) > operand_length && (int) strlen(current_line->comment_txt) > 0) + operand_length = (int) strlen(current_line->operand_txt); + if(operand_length > 21) + operand_length = 21; + } + + /** Entête **/ + /* Trait */ + strcpy(param->buffer_line,"------+----"); + for(i=0; ibuffer_line,"-"); + strcat(param->buffer_line,"------+-------------+----+---------+------+-----------------------+-------------------------------------------------------------------\n"); + fwrite(param->buffer_line,1,strlen(param->buffer_line),fd); + /* Libellé */ + strcpy(param->buffer_line," Line | # File"); + for(i=0; ibuffer_line," "); + strcat(param->buffer_line," Line | Line Type | MX | Reloc | Size | Address Object Code | Source Code \n"); + fwrite(param->buffer_line,1,strlen(param->buffer_line),fd); + /* Trait */ + strcpy(param->buffer_line,"------+----"); + for(i=0; ibuffer_line,"-"); + strcat(param->buffer_line,"------+-------------+----+---------+------+-----------------------+-------------------------------------------------------------------\n"); + fwrite(param->buffer_line,1,strlen(param->buffer_line),fd); + + /*** Traitement des lignes ***/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ne prend pas les lignes invalides */ + if(current_line->is_valid == 0) + continue; + + /* Pour une Macro, on ne prend que la ligne d'appel */ + if(current_line->type == LINE_MACRO && current_line->is_in_source == 0) + continue; + /* On ne prend pas les Directive, sauf si elles ont un Label utilisé */ + if(current_line->type == LINE_DIRECTIVE && current_line->is_in_source == 0) + continue; + + /** Création de la ligne **/ + /* En cas de Dump en erreur, on peu avoir des Tailles de lignes avec des FFFFF */ + nb_byte = current_line->nb_byte; + if(nb_byte == 0xFFFFF) + nb_byte = 0; + + /* Numéro de la ligne + Nom du fichier + Numéro de la ligne du fichier */ + sprintf(buffer_format,"%%5d | %%2d %%%ds %%5d",file_length); + sprintf(param->buffer_line,buffer_format,current_line->line_number,current_line->file->file_number,current_line->file->file_name,current_line->file_line_number); + + /* Type | MX | Reloc | Taille | Address */ + sprintf(¶m->buffer_line[strlen(param->buffer_line)]," | %s | %s%s |%s| %4d | %02X/%04X", + (current_line->is_dum==1)?"Dum ":line_type_tab[current_line->type], + current_line->m,current_line->x,current_line->reloc,nb_byte,current_line->bank,(WORD)current_line->address); + + /* Découpage */ + if(current_line->type == LINE_COMMENT) + { + strcat(param->buffer_line," | "); + strcat(param->buffer_line,current_line->line_data); + } + else + { + /** Code objet **/ + if(current_line->type == LINE_CODE) + { + /* Opcode Bye + Operand Byte */ + sprintf(param->buffer_value," : %02X ",current_line->opcode_byte); + for(i=0; ibuffer_value[strlen(param->buffer_value)],"%02X ",current_line->operand_byte[i]); + strcat(param->buffer_value," "); + } + else if(current_line->type == LINE_DATA) + { + /* Operand Byte */ + strcpy(param->buffer_value," : "); + for(i=0; ibuffer_value[strlen(param->buffer_value)],"%02X ",current_line->data[i]); + strcat(param->buffer_value," "); + } + else + strcpy(param->buffer_value," "); + param->buffer_value[15] = '|'; + param->buffer_value[16] = '\0'; + strcat(param->buffer_line,param->buffer_value); + + /* Label */ + sprintf(buffer_format," %%-%ds",label_length); + sprintf(param->buffer_value,buffer_format,current_line->label_txt); + strcat(param->buffer_line,param->buffer_value); + + /* Opcode */ + sprintf(buffer_format," %%-%ds",opcode_length); + sprintf(param->buffer_value,buffer_format,(current_line->type == LINE_EMPTY)?"":current_line->opcode_txt); + strcat(param->buffer_line,param->buffer_value); + + /* Operand */ + sprintf(buffer_format," %%-%ds",operand_length); + sprintf(param->buffer_value,buffer_format,(current_line->type == LINE_EMPTY)?"":current_line->operand_txt); + strcat(param->buffer_line,param->buffer_value); + + /* Commentaire */ + strcat(param->buffer_line,current_line->comment_txt); + } + + /* Fin de ligne */ + strcat(param->buffer_line,"\n"); + + /* Ecriture de la ligne dans le fichier */ + fwrite(param->buffer_line,1,strlen(param->buffer_line),fd); + + /** On va finaliser la partie Data > 4 bytes **/ + if(current_line->type == LINE_DATA && nb_byte > 4) + { + for(i=4; i= 4 ? 4 : nb_byte-i; + + /* Ligne vide */ + strcpy(param->buffer_line," | "); + for(j=0; jbuffer_line," "); + strcat(param->buffer_line," | | | | | "); + for(j=0; j<4; j++) + { + if(j < nb_byte_left) + sprintf(¶m->buffer_line[strlen(param->buffer_line)],"%02X ",current_line->data[i+j]); + else + strcat(param->buffer_line," "); + } + strcat(param->buffer_line,"|\n"); + fwrite(param->buffer_line,1,strlen(param->buffer_line),fd); + } + } + } + + /* Trait */ + strcpy(param->buffer_line,"------+----"); + for(i=0; ibuffer_line,"-"); + strcat(param->buffer_line,"------+-------------+----+---------+------+-----------------------+-------------------------------------------------------------------\n"); + fwrite(param->buffer_line,1,strlen(param->buffer_line),fd); + + /* Fermeture du fichier */ + fclose(fd); + + /* OK */ + return(0); +} + + +/*****************************************************************************/ +/* mem_free_sourcefile() : Libération mémoire de la structure source_file. */ +/*****************************************************************************/ +void mem_free_sourcefile(struct source_file *current_sourcefile, int free_line) +{ + struct source_line *current_line; + struct source_line *next_line; + + if(current_sourcefile) + { + if(current_sourcefile->file_path) + free(current_sourcefile->file_path); + + if(current_sourcefile->file_name) + free(current_sourcefile->file_name); + + if(current_sourcefile->data) + free(current_sourcefile->data); + + if(current_sourcefile->tab_line) + free(current_sourcefile->tab_line); + + if(free_line == 1) + { + for(current_line=current_sourcefile->first_line; current_line; ) + { + next_line = current_line->next; + mem_free_sourceline(current_line); + current_line = next_line; + } + } + + free(current_sourcefile); + } +} + +/***********************************************************************/ diff --git a/Source/a65816_File.h b/Source/a65816_File.h new file mode 100644 index 0000000..9063b2e --- /dev/null +++ b/Source/a65816_File.h @@ -0,0 +1,35 @@ +/***********************************************************************/ +/* */ +/* a65816_File.h : Header pour la gestion des fichiers. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +struct source_file +{ + char *file_path; + char *file_name; + int file_number; + + unsigned char *data; + + int nb_line; + char **tab_line; + + struct source_line *first_line; /* Ligne de ce fichier Source */ + struct source_line *last_line; + + struct source_file *next; +}; + +int LoadAllSourceFile(char *,char *,struct omf_segment *); +struct source_file *LoadOneSourceFile(char *,char *,int); +struct source_file *LoadOneBinaryFile(char *,char *,int); +int BuildObjectCode(struct omf_segment *); +int CreateOutputFile(char *,struct omf_segment *,struct omf_project *); +int BuildObjectFile(char *,struct omf_segment *,struct omf_project *); +int BuildSingleObjectFile(char *,int,struct omf_project *); +void mem_free_sourcefile(struct source_file *,int); + +/***********************************************************************/ diff --git a/Source/a65816_Line.c b/Source/a65816_Line.c new file mode 100644 index 0000000..2cc4677 --- /dev/null +++ b/Source/a65816_Line.c @@ -0,0 +1,3324 @@ +/***********************************************************************/ +/* */ +/* a65816_Line.c : Module pour la gestion des lignes . */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +#include +#include +#include +#include +#include + +#include "Dc_Library.h" +#include "a65816_Macro.h" +#include "a65816_File.h" +#include "a65816_Code.h" +#include "a65816_Line.h" +#include "a65816_OMF.h" + + +char *opcode_list[] = +{ + "ADC","ADCL","AND","ANDL","ASL", + "BCC","BLT","BCS","BGE","BEQ","BIT","BMI","BNE","BPL","BRA","BRK","BRL","BVC","BVS", + "CLC","CLD","CLI","CLV","CMP","CMPL","COP","CPX","CPY", + "DEC","DEX","DEY", + "EOR","EORL", + "INC","INX","INY", + "JMP","JML","JMPL","JSR","JSL", + "LDA","LDAL","LDX","LDY","LSR", + "MVN","MVP", + "NOP", + "ORA","ORAL", + "PEA","PEI","PER","PHA","PHB","PHD","PHK","PHP","PHX","PHY","PLA","PLB","PLD","PLP","PLX","PLY", + "REP","ROL","ROR","RTI","RTL","RTS", + "SBC","SBCL","SEC","SED","SEI","SEP","STA","STAL","STP","STX","STY","STZ", + "TAX","TAY","TCD","TCS","TDC","TRB","TSB","TSC","TSX","TXA","TXS","TXY","TYA","TYX", + "WAI","WDM", + "XBA","XCE", + NULL +}; + +/* DA : Define Address (2 Bytes) */ +/* DW : Define Word (2 Bytes) */ +/* DDB : Define Double Byte (2 Bytes) */ +/* DFB : DeFine Byte (1 Byte) */ +/* DB : Define Byte (1 Byte) */ +/* ADR : Define Long Address (3 Bytes) */ +/* ADRL : Define Long Address (4 Bytes) */ +/* HEX : Define HEX data (1 Byte) */ +/* DS : Define Storage (X Bytes) = DS 10 (put $00 in 10 bytes), DS 10,$80 (put $80 in 10 bytes), DS \,$80 (put $80 until next page) */ + +/* ASC : Ascii ("" positive, '' negative) */ +/* DCI : Dextral Character Inverted */ +/* INV : Inverse Text */ +/* FLS : Flasing Text */ +/* REV : Reverse */ +/* STR : String with leading length (1 byte) */ +/* STRL : String with leading length (2 bytes) */ + +char *data_list[] = +{ + "DA","DW","DDB","DFB","DB","ADR","ADRL","HEX","DS", + "DC","DE", /* ? */ + "ASC","DCI","INV","FLS","REV","STR","STRL", + "CHK", /* Remplace par 1 Byte de Checksum */ + NULL +}; + +char *directive_list[] = +{ + "ANOP","ORG","PUT","PUTBIN", /* PUTBIN n'existe pas dans Merlin 16+ */ + "START","END", + "DUM","DEND", + "MX","XC","LONGA","LONGI", + "USE","USING", + "REL","DSK","LNK","SAV", + "TYP", + "IF","DO","ELSE","FIN", + "LUP","--^", + "ERR","DAT", + "AST","CYC","EXP","LST","LSTDO","PAG","TTL","SKP","TR","KBD","PAU","SW","USR", /* On ne fait rien avec ces Directives */ + NULL +}; + +char *equivalence_list[] = /* Equivalence ou ]Variable */ +{ + "EQU","=", + NULL +}; + +/** Address Mode ** +A Implicit +addr2 Absolute +(addr2,X) Absolute Indexed,X Indirect +addr2,X Absolute Indexed,X +addr2,Y Absolute Indexed,Y +(addr2) Absolute Indirect +[addr2] Absolute Indirect Long +addr3 Absolute Long +addr3,X Absolute Long Indexed,X +dp Direct Page +dp,X Direct Page Indexed,X +dp,Y Direct Page Indexed,Y +(dp) Direct Page Indirect +[dp] Direct Page Indirect Long +(dp,X) Direct Page Indexed Indirect,X +(dp),Y Direct Page Indirect Indexed,Y +[dp],Y Direct Page Indirect Long Indexed,Y +#const Immediate +relative1 Program Counter Relative +relative2 Program Counter Relative Long +(sr,S),Y Stack Relative Indirect Indexed,Y +label Stack PC Relative Long +sr,S Stack Relative +*/ + +static int IsLocalLabel(char *,struct omf_segment *); +static int ProcessSourceAsteriskLine(struct source_line *,struct source_line *,struct source_file *,struct omf_segment *); +static int ProcessMacroAsteriskLine(struct macro_line *,struct macro_line *,struct macro *,struct omf_segment *); +static int ProcessSourceLineLocalLabel(struct source_line *,struct source_line *,struct omf_segment *); +static int ProcessMacroLineLocalLabel(struct macro_line *,struct macro_line *,struct macro *,struct omf_segment *); +static int ProcessSourceLineVariableLabel(struct source_line *,struct source_line *,struct omf_segment *); +static int ProcessMacroLineVariableLabel(struct macro_line *,struct macro_line *,struct macro *,struct omf_segment *); +static void AddDateLine(struct source_line *,struct omf_segment *); + +/****************************************************/ +/* DecodeLineType() : Détermine le type de ligne. */ +/****************************************************/ +int DecodeLineType(struct source_line *first_line, struct macro *current_macro, struct omf_segment *current_omfsegment, struct omf_project *current_omfproject) +{ + int i, nb_error, nb_label, do_level, do_status, nb_global, found; + int64_t value_wdc; + char *str_temp; + char *new_label; + char **tab_label; + struct item *current_item; + struct source_file *first_file; + struct source_line *current_line; + struct source_line *new_line; + struct source_line *last_line; + struct source_line *do_line; + struct source_line *else_line; + struct source_line *fin_line; + char *new_opcode; + struct global *current_global; + char opcode[1024]; + char macro_name[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /* Init */ + nb_error = 0; + + /*** Passe toutes les lignes en revue ***/ + for(current_line=first_line; current_line; current_line=current_line->next) + { + /* Ligne déjà connue */ + if(current_line->type != LINE_UNKNOWN) + continue; + + /** Ligne vide **/ + if(strlen(current_line->label_txt) == 0 && strlen(current_line->opcode_txt) == 0 && strlen(current_line->operand_txt) == 0) + { + current_line->type = LINE_EMPTY; + continue; + } + if(strlen(current_line->label_txt) > 0 && strlen(current_line->opcode_txt) == 0) + { + current_line->type = LINE_EMPTY; + continue; + } + + /** Ligne ERR Expression dont l'évaluation se fait à la fin **/ + if(!my_stricmp(current_line->opcode_txt,"ERR") && strlen(current_line->operand_txt)) + { + current_line->type = LINE_CODE; + continue; + } + + /** Ligne DAT à laquelle ont ajouter la Date sous forme de Texte **/ + if(!my_stricmp(current_line->opcode_txt,"DAT")) + { + current_line->type = LINE_DIRECTIVE; + + /* On doit ajouter une ligne de Texte avec la date */ + if(strlen(current_line->operand_txt) > 0) + AddDateLine(current_line,current_omfsegment); + continue; + } + + /** Ligne définissant un point d'entrée Global pour les InterSeg **/ + if(strlen(current_line->label_txt) > 0 && !my_stricmp(current_line->opcode_txt,"ENT")) + { + current_line->type = LINE_GLOBAL; + continue; + } + + /** Ligne définissant une ou plusieurs entrées Global pour les InterSeg **/ + if(strlen(current_line->label_txt) == 0 && !my_stricmp(current_line->opcode_txt,"ENT") && strlen(current_line->operand_txt) > 0) + { + /* Plusieurs Labels EXT sous la forme Label1,Label2,Label3... => Création de nouvelles lignes */ + tab_label = BuildUniqueListFromText(current_line->operand_txt,',',&nb_label); + if(tab_label == NULL) + { + /* Error */ + printf(" => Error : Can't allocate memory to process line.\n"); + return(1); + } + + /* On va conserver ces Labels pour les traiter après le chargement des lignes */ + for(i=0; itype = LINE_EMPTY; + mem_free_list(nb_label,tab_label); + continue; + } + + /** Ligne définissant un label Externe à ce segment **/ + if(strlen(current_line->label_txt) > 0 && !my_stricmp(current_line->opcode_txt,"EXT")) + { + current_line->type = LINE_EXTERNAL; + continue; + } + + /** Ligne définissant un|plusieurs label Externe à ce segment **/ + if(strlen(current_line->label_txt) == 0 && !my_stricmp(current_line->opcode_txt,"EXT") && strlen(current_line->operand_txt) > 0) + { + /* On va inverser le Label et l'Operand : EXT Label => Label EXT */ + if(strchr(current_line->operand_txt,',') == NULL) + { + /* Un seul label EXT */ + str_temp = current_line->label_txt; + current_line->label_txt = current_line->operand_txt; + current_line->operand_txt = str_temp; + current_line->type = LINE_EXTERNAL; + continue; + } + else + { + /* Plusieurs Labels EXT sous la forme Label1,Label2,Label3... => Création de nouvelles lignes */ + tab_label = BuildUniqueListFromText(current_line->operand_txt,',',&nb_label); + if(tab_label == NULL) + { + /* Error */ + printf(" => Error : Can't allocate memory to process line.\n"); + return(1); + } + + /* Finalement aucun Label */ + if(nb_label == 0) + { + mem_free_list(nb_label,tab_label); + current_line->type = LINE_EMPTY; + continue; + } + + /** On va devoir créer des lignes pour chacun des Labels **/ + /* Ligne courrante */ + new_label = strdup(tab_label[0]); + if(new_label == NULL) + { + /* Error */ + printf(" => Error : Can't allocate memory to process line.\n"); + return(1); + } + free(current_line->label_txt); + current_line->label_txt = new_label; + strcpy(current_line->operand_txt,""); + current_line->type = LINE_EXTERNAL; + + /* Lignes Suivantes */ + for(i=1; i Error : Can't allocate memory to process line.\n"); + return(1); + } + + /* Nouveau Label (on part du fond du tableau) */ + new_line->label_txt = strdup(tab_label[nb_label-i]); + if(new_line->label_txt == NULL) + { + /* Error */ + mem_free_sourceline(new_line); + mem_free_list(nb_label,tab_label); + printf(" => Error : Can't allocate memory to process line.\n"); + return(1); + } + + /* Attache la ligne */ + new_line->next = current_line->next; + current_line->next = new_line; + } + + /* Libération mémoire */ + mem_free_list(nb_label,tab_label); + continue; + } + } + + /** Identification du type de ligne en utilisant l'opcode **/ + if(strlen(current_line->opcode_txt) > 0) + { + /*** Macro (on place la détection de Macro avant la détection des Opcodes car un WAIT en macro pourrait être interpretté comme un WAI du 65c816) ***/ + /* Appel via PMC ou >>> */ + if((!my_stricmp(current_line->opcode_txt,"PMC") || !my_stricmp(current_line->opcode_txt,">>>")) && strlen(current_line->operand_txt) > 0) + { + /* On va isoler le nom de la macro (car il peut être collé aux paramètres) */ + strcpy(macro_name,current_line->operand_txt); + for(i=0; i<(int)strlen(macro_name); i++) + if(macro_name[i] == ',' || macro_name[i] == '.' || macro_name[i] == '/' || macro_name[i] == '-' || macro_name[i] == '(' || macro_name[i] == ' ') + { + macro_name[i] = '\0'; + break; + } + + /* Recherche cette Macro */ + my_Memory(MEMORY_SEARCH_MACRO,macro_name,¤t_item,current_omfsegment); + if(current_item != NULL) + { + current_line->type = LINE_MACRO; + current_line->macro = (struct macro *) current_item; + continue; + } + } + else + { + /* Appel avec le nom de la macro */ + my_Memory(MEMORY_SEARCH_MACRO,current_line->opcode_txt,¤t_item,current_omfsegment); + if(current_item != NULL) + { + current_line->type = LINE_MACRO; + current_line->macro = (struct macro *) current_item; + continue; + } + } + + /*** Opcode ***/ + if(current_item == NULL) + { + my_Memory(MEMORY_SEARCH_OPCODE,current_line->opcode_txt,¤t_item,current_omfsegment); + if(current_item != NULL) + { + current_line->type = LINE_CODE; + continue; + } + + /*** Opcode avec une lettre derrière : LDA\ ou LDA: (ni D ni L) ***/ + if(strlen(current_line->opcode_txt) == 4) + { + if(toupper(current_line->opcode_txt[3]) != 'L' && toupper(current_line->opcode_txt[3]) != 'D') + { + strcpy(opcode,current_line->opcode_txt); + opcode[3] = '\0'; + my_Memory(MEMORY_SEARCH_OPCODE,opcode,¤t_item,current_omfsegment); + if(current_item != NULL) + { + current_line->opcode_txt[3] = '\0'; + current_line->type = LINE_CODE; + current_line->no_direct_page = 1; /* Il y a un caractère derrière l'opcode pour empêcher le Page Direct */ + continue; + } + } + } + } + + /*** Data ***/ + if(current_item == NULL) + { + my_Memory(MEMORY_SEARCH_DATA,current_line->opcode_txt,¤t_item,current_omfsegment); + if(current_item != NULL) + { + current_line->type = LINE_DATA; + continue; + } + } + + /*** Directive ***/ + if(current_item == NULL) + { + my_Memory(MEMORY_SEARCH_DIRECTIVE,current_line->opcode_txt,¤t_item,current_omfsegment); + if(current_item != NULL) + { + current_line->type = LINE_DIRECTIVE; + + /* On repère les REL (mais on entiet pas compte si on est sur un project multi-fixed) */ + if(!my_stricmp(current_line->opcode_txt,"REL") && current_omfproject->is_multi_fixed != 1) + current_omfsegment->is_relative = 1; + + continue; + } + } + + /*** Equivalence ou Variable ***/ + if(current_item == NULL) + { + my_Memory(MEMORY_SEARCH_DIREQU,current_line->opcode_txt,¤t_item,current_omfsegment); + if(current_item != NULL) + { + if(current_line->label_txt[0] == ']') + current_line->type = LINE_VARIABLE; + else + current_line->type = LINE_EQUIVALENCE; + continue; + } + } + } + + /* Erreur : Ligne toujours inconnue :-( */ + if(current_line->type == LINE_UNKNOWN) + { + if(current_macro != NULL) + printf(" => [Error] Unknown Macro line '%s' from Macro file '%s' (line %d), inserted in source file '%s' (line %d).\n",current_line->line_data,current_macro->file_name,current_macro->file_line_number,current_line->file->file_name,current_line->file_line_number); + else + printf(" => [Error] Unknown line '%s' in source file '%s' (line %d).\n",current_line->line_data,current_line->file->file_name,current_line->file_line_number); + nb_error++; + } + } + + /*** On ne fait pas le travail d'analyse des ENT dans les Macro ***/ + if(current_macro == NULL) + { + /********************************************************************/ + /** Y a t'il des ENT qui ont été déclarées en ENT Label1,Label2... **/ + /********************************************************************/ + my_Memory(MEMORY_GET_GLOBAL_NB,&nb_global,NULL,current_omfsegment); + for(i=1; i<=nb_global; i++) + { + /* On récupère un Label ENT */ + my_Memory(MEMORY_GET_GLOBAL,&i,¤t_global,current_omfsegment); + + /* Cherche une ligne avec ce Label */ + for(found=0,current_line = first_file->first_line; current_line; current_line = current_line->next) + { + if(!strcmp(current_line->label_txt,current_global->name) && current_line->type == LINE_GLOBAL) + { + /* On a déjà le ENT sur la ligne du label => rien à faire */ + found = 1; + break; + } + else if(!strcmp(current_line->label_txt,current_global->name)) + { + /* On crée une ligne ENT avec le label */ + new_line = DuplicateSourceLine(current_line); + if(new_line == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to Duplicate Line %d in Source file '%s'",current_line->file_line_number,current_line->file->file_path); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + new_opcode = strdup("ENT"); + if(new_opcode == NULL) + { + mem_free_sourceline(new_line); + sprintf(param->buffer_error,"Impossible to allocate memory to Duplicate Line %d in Source file '%s'",current_line->file_line_number,current_line->file->file_path); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Modifie les valeurs */ + strcpy(current_line->operand_txt,""); /* On vide l'Operande de la ligne ENT */ + free(current_line->opcode_txt); + current_line->opcode_txt = new_opcode; /* Le nouvel Opcode est ENT */ + current_line->type = LINE_GLOBAL; /* Cette ligne est désormais une GLOBAL */ + strcpy(new_line->label_txt,""); /* On vide le label pour éviter les doublons */ + + /* Attache la nouvelle ligne */ + new_line->next = current_line->next; + current_line->next = new_line; + + /* Label ENT traité */ + found = 1; + break; + } + } + + /* On a pas trouvé de ligne avec ce Label => on la place au niveau du ENT Label1,Label2... */ + if(found == 0) + { + /* On crée une ligne ENT avec le label en la placant apreès la ligne ENT Label1,Label2...*/ + new_line = DuplicateSourceLine(current_global->source_line); + if(new_line == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to Duplicate Line %d in Source file '%s'",current_global->source_line->file_line_number,current_global->source_line->file->file_path); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + new_label = strdup(current_global->name); + if(new_label == NULL) + { + mem_free_sourceline(new_line); + sprintf(param->buffer_error,"Impossible to allocate memory to Duplicate Line %d in Source file '%s'",current_global->source_line->file_line_number,current_global->source_line->file->file_path); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Modifie les valeurs */ + strcpy(new_line->operand_txt,""); /* On vide l'Operande de la ligne ENT */ + free(new_line->label_txt); + new_line->label_txt = new_label; /* Place le Label */ + new_line->type = LINE_GLOBAL; /* Cette ligne est désormais une GLOBAL */ + + /* Attache la nouvelle ligne en dessous */ + new_line->next = current_global->source_line->next; + current_global->source_line->next = new_line; + } + } + } + + /*** On ne fait pas le travail d'analyse des DO dans les Macro ***/ + if(current_macro == NULL) + { + /************************************************************************************/ + /*** 1ère passe pour marquer les niveaux des DO-ELSE-FIN et valider l'imbrication ***/ + /************************************************************************************/ + do_level = 0; + for(current_line=first_line; current_line; current_line=current_line->next) + { + /* On conserve la dernière ligne du fichier pour le message d'erreur */ + last_line = current_line; + + /* Ligne définissant une nouvelle condition DO-FIN */ + if(current_line->type == LINE_DIRECTIVE && (!my_stricmp(current_line->opcode_txt,"DO") || !my_stricmp(current_line->opcode_txt,"IF"))) + { + do_level++; + current_line->do_level = do_level; + continue; + } + + /* Ligne définissant l'inversion d'une condition DO-ELSE_FIN */ + if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"ELSE")) + { + current_line->do_level = do_level; + if(do_level == 0) + { + printf(" => [Error] ELSE directive found in source file '%s' at line %d doesn't match with a previous (missing) DO or IF.\n",current_line->file->file_name,current_line->file_line_number); + return(1); + } + continue; + } + + /* Ligne définissant la fin d'un DO-FIN */ + if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"FIN")) + { + current_line->do_level = do_level; + do_level--; + if(do_level < 0) + { + printf(" => [Error] FIN directive found in source file '%s' at line %d doesn't match with a previous (missing) DO or IF.\n",current_line->file->file_name,current_line->file_line_number); + return(1); + } + continue; + } + + /* Ligne normale */ + current_line->do_level = do_level; + } + if(do_level > 0) + { + printf(" => [Error] Missing FIN directive in source file '%s' (due to previous usage of a DO or IF directive).\n",last_line->file->file_name); + return(1); + } + + /***********************************************************************************/ + /*** 2ème passe pour évaluer les conditions DO et invalider les lignes du source ***/ + /***********************************************************************************/ + for(do_line=first_line; do_line; do_line=do_line->next) + { + /* Ligne définissant une première condition DO */ + if(do_line->type == LINE_DIRECTIVE && !my_stricmp(do_line->opcode_txt,"DO")) + { + /* Evaluation de la condition */ + do_status = QuickConditionEvaluate(do_line,&value_wdc,current_omfsegment); + + /* Cherche la ligne FIN */ + for(fin_line=do_line; fin_line; fin_line=fin_line->next) + if(fin_line->type == LINE_DIRECTIVE && !my_stricmp(fin_line->opcode_txt,"FIN") && do_line->do_level == fin_line->do_level) + break; + + /* Cherche une éventuelle ligne ELSE */ + for(else_line=do_line; else_line!=fin_line; else_line=else_line->next) + if(else_line->type == LINE_DIRECTIVE && !my_stricmp(else_line->opcode_txt,"ELSE") && do_line->do_level == else_line->do_level) + break; + if(else_line == fin_line) + else_line = NULL; + + /** On invalide DO - ELSE/FIN **/ + if(do_status == STATUS_DONT) + { + for(current_line=do_line->next; current_line!=((else_line!=NULL)?else_line:fin_line); current_line=current_line->next) + current_line->is_valid = 0; + } + /** On invalide ELSE - FIN **/ + else if(do_status == STATUS_DO && else_line != NULL) + { + for(current_line=else_line->next; current_line!=fin_line; current_line=current_line->next) + current_line->is_valid = 0; + } + + /** On ne sait pas : On continue à partie du FIN **/ + do_line = fin_line; + } + } + } + + /* Renvoie le nombre d'erreur */ + return(nb_error); +} + + +/****************************************************************************************/ +/* ProcessAllAsteriskLine() : Remplace les '*' dans les lignes de Code et les Macros. */ +/****************************************************************************************/ +int ProcessAllAsteriskLine(struct omf_segment *current_omfsegment) +{ + int i, error, nb_macro; + struct source_file *first_file; + struct source_line *current_line; + struct source_line *last_line = NULL; + struct macro *current_macro; + + /* Récupère le fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /** On traite les lignes du Source **/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + if(current_line->next == NULL) + last_line = current_line; + error = ProcessSourceAsteriskLine(first_file->first_line,last_line,first_file,current_omfsegment); + if(error) + return(1); + + /** On traite les Macros **/ + my_Memory(MEMORY_GET_MACRO_NB,&nb_macro,NULL,current_omfsegment); + for(i=1; i<=nb_macro; i++) + { + my_Memory(MEMORY_GET_MACRO,&i,¤t_macro,current_omfsegment); + + /** Traite les lignes de cette Macro **/ + error = ProcessMacroAsteriskLine(current_macro->first_line,current_macro->last_line,current_macro,current_omfsegment); + if(error) + return(1); + } + + /* OK */ + return(0); +} + + +/*****************************************************************************/ +/* ProcessSourceAsteriskLine() : Remplace les '*' dans les lignes de Code. */ +/*****************************************************************************/ +static int ProcessSourceAsteriskLine(struct source_line *first_line, struct source_line *last_line, struct source_file *first_file, struct omf_segment *current_omfsegment) +{ + int use_address; + struct source_line *previous_line; + struct source_line *current_line; + struct source_line *new_line; + char label_name[1024]; + char buffer_error[1024]; + + /*** Passe toutes les lignes en revue ***/ + for(previous_line=NULL, current_line=first_line; current_line; previous_line=current_line, current_line=current_line->next) + { + /* On ne traite pas les commentaires */ + if(current_line->type == LINE_EMPTY || current_line->type == LINE_COMMENT || current_line->type == LINE_GLOBAL || current_line->is_valid == 0) + continue; + + /** Cas particulier des ]Label = * ou des Label = * **/ + if(strlen(current_line->label_txt) > 0 && !strcmp(current_line->opcode_txt,"=") && !strcmp(current_line->operand_txt,"*")) + { + /* On convertit cette ligne en ligne vide */ + strcpy(current_line->opcode_txt,""); + strcpy(current_line->operand_txt,""); + current_line->type = LINE_EMPTY; + continue; + } + + /** On ne cherche que dans l'Operande **/ + if(strchr(current_line->operand_txt,'*') != NULL) + { + /** Peut t'on détecter un * utilisé comme valeur ? **/ + use_address = UseCurrentAddress(current_line->operand_txt,&buffer_error[0],current_line); + if(strlen(buffer_error) > 0) + { + printf(" Error : Impossible to analyze Operand '%s' in source file '%s' (line %d) : %s.\n", + current_line->operand_txt,current_line->file->file_name,current_line->file_line_number,buffer_error); + return(1); + } + if(use_address == 0) + continue; + + /** On va remplacer le * par un label unique **/ + /* Création d'un Label unique ANOP */ + GetUNID(&label_name[0]); + + /** Création d'un Ligne vide ANOP avec le label **/ + new_line = (struct source_line *) calloc(1,sizeof(struct source_line)); + if(new_line == NULL) + { + printf(" Error : Impossible to allocate memory to create new Empty line.\n"); + return(1); + } + new_line->file = current_line->file; + new_line->file_line_number = current_line->file_line_number; + new_line->line_number = current_line->line_number; + new_line->is_in_source = 1; + new_line->is_valid = 1; + strcpy(new_line->reloc," "); + new_line->label_txt = strdup(label_name); + new_line->opcode_txt = strdup(""); + new_line->operand_txt = strdup(""); + new_line->comment_txt = strdup(""); + strcpy(new_line->m,current_line->m); + strcpy(new_line->x,current_line->x); + new_line->address = current_line->address; + new_line->operand_value = current_line->operand_value; + new_line->operand_address_long = current_line->operand_address_long; + new_line->bank = current_line->bank; + new_line->type_aux = current_line->type_aux; /* On conserve l'information d'inclusion dans le corps d'une Macro */ + new_line->is_inside_macro = current_line->is_inside_macro; + if(new_line->label_txt == NULL || new_line->opcode_txt == NULL || new_line->operand_txt == NULL || new_line->comment_txt == NULL) + { + printf(" Error : Impossible to allocate memory to populate new Empty line.\n"); + mem_free_sourceline(new_line); + return(1); + } + new_line->type = LINE_EMPTY; + + /* Attachement de la ligne au dessus */ + new_line->next = current_line; + if(previous_line == NULL) + first_file->first_line = new_line; + else + previous_line->next = new_line; + + /** Remplace le * par un Label unique **/ + ReplaceCurrentAddressInOperand(¤t_line->operand_txt,label_name,&buffer_error[0],current_line); + if(strlen(buffer_error) > 0) + { + printf(" Error : Impossible to replace '*' in Operand '%s' in source file '%s' (line %d) : %s.\n", + current_line->operand_txt,current_line->file->file_name,current_line->file_line_number,buffer_error); + return(1); + } + } + } + + /* OK */ + return(0); +} + + +/******************************************************************************/ +/* ProcessMacroAsteriskLine() : Remplace les '*' dans les lignes des Macro. */ +/******************************************************************************/ +static int ProcessMacroAsteriskLine(struct macro_line *first_line, struct macro_line *last_line, struct macro *current_macro, struct omf_segment *current_omfsegment) +{ + int use_address; + struct macro_line *previous_line; + struct macro_line *current_line; + struct macro_line *new_line; + char label_name[1024]; + char buffer_error[1024]; + + /*** Passe toutes les lignes en revue ***/ + for(previous_line=NULL, current_line=first_line; current_line; previous_line=current_line, current_line=current_line->next) + { + /** Cas particulier des ]Label = * ou des Label = * **/ + if(strlen(current_line->label) > 0 && !strcmp(current_line->opcode,"=") && !strcmp(current_line->operand,"*")) + { + /* On convertit cette ligne en ligne vide */ + strcpy(current_line->opcode,""); + strcpy(current_line->operand,""); + continue; + } + + /** On ne cherche quand dans l'Operande **/ + if(strchr(current_line->operand,'*') != NULL) + { + /** Peut t'on détecter un * utilisé comme valeur ? **/ + use_address = UseCurrentAddress(current_line->operand,&buffer_error[0],NULL); + if(strlen(buffer_error) > 0) + { + printf(" Error : Impossible to analyze Operand '%s' in Macro '%s' : %s.\n", + current_line->operand,current_macro->name,buffer_error); + return(1); + } + if(use_address == 0) + continue; + + /** On va remplacer le * par un label unique **/ + /* Création d'un Label unique ANOP */ + GetUNID(&label_name[0]); + + /** Création d'un Ligne vide ANOP avec le label **/ + new_line = (struct macro_line *) calloc(1,sizeof(struct macro_line)); + if(new_line == NULL) + { + printf(" Error : Impossible to allocate memory to create new Empty Macro line.\n"); + return(1); + } + new_line->label = strdup(label_name); + new_line->opcode = strdup(""); + new_line->operand = strdup(""); + new_line->comment = strdup(""); + if(new_line->label == NULL || new_line->opcode == NULL || new_line->operand == NULL || new_line->comment == NULL) + { + printf(" Error : Impossible to allocate memory to populate new Empty Macro line.\n"); + mem_free_macroline(new_line); + return(1); + } + + /* Attachement de la ligne au dessus */ + new_line->next = current_line; + if(previous_line == NULL) + current_macro->first_line = new_line; + else + previous_line->next = new_line; + + /** Remplace le * par un Label unique **/ + ReplaceCurrentAddressInOperand(¤t_line->operand,label_name,&buffer_error[0],NULL); + if(strlen(buffer_error) > 0) + { + printf(" Error : Impossible to replace '*' in Operand '%s' in Macro '%s' : %s.\n", + current_line->operand,current_macro->name,buffer_error); + return(1); + } + } + } + + /* OK */ + return(0); +} + + +/*************************************************************/ +/* BuildLabelTable() : Construction des tables des Labels. */ +/*************************************************************/ +int BuildLabelTable(struct omf_segment *current_omfsegment) +{ + struct label *current_label; + struct source_line *current_line; + struct source_file *first_file; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Récupère le fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /** Passe toutes les lignes en revue **/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes non valides */ + if(current_line->is_valid == 0) + continue; + + /* On ne prend que le lignes avec label */ + if(strlen(current_line->label_txt) == 0) + continue; + + /* On ne prend pas les Label locaux ou les Variables */ + if(current_line->label_txt[0] == ':' || current_line->label_txt[0] == ']') + continue; + + /* On ne prend pas les Equivalence */ + if(current_line->type == LINE_EQUIVALENCE) + continue; + + /* On ne prend pas les External */ + if(current_line->type == LINE_EXTERNAL) + continue; + + /* On ne prend pas les Label dans les Macro */ + if(current_line->type == LINE_DIRECTIVE && current_line->type_aux == LINE_MACRO_DEF) + continue; + if(current_line->is_inside_macro == 1) + continue; + + /* On ne prend pas les Labels dans les LUP */ + if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"LUP")) + continue; + if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"--^")) + continue; + + /** Allocation de la structure Label **/ + current_label = (struct label *) calloc(1,sizeof(struct label)); + if(current_label == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for structure label"); + current_label->name = strdup(current_line->label_txt); + if(current_label->name == NULL) + { + free(current_label); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for 'name' from structure label"); + } + current_label->line = current_line; + + /* Un label Global est un label comme un autre */ + if(current_line->type == LINE_GLOBAL) + current_label->is_global = 1; + + /* Déclaration de la structure */ + my_Memory(MEMORY_ADD_LABEL,current_label,NULL,current_omfsegment); + } + + /* Tri les Labels */ + my_Memory(MEMORY_SORT_LABEL,NULL,NULL,current_omfsegment); + + /* OK */ + return(0); +} + + +/************************************************************************/ +/* BuildEquivalenceTable() : Construction des tables des Equivalence. */ +/************************************************************************/ +int BuildEquivalenceTable(struct omf_segment *current_omfsegment) +{ + int i, j, nb_equivalence, nb_element, modified, nb_modified; + struct equivalence *current_equivalence; + struct equivalence *replace_equivalence; + struct source_line *current_line; + struct source_file *first_file; + char *new_value; + char **tab_element; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Récupère le fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /** Passe toutes les lignes en revue (certaines equivalences provenant des fichiers macro sont déjà enregistrées) **/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes non valides */ + if(current_line->is_valid == 0) + continue; + + /* On ne prend que les Equivalence */ + if(current_line->type != LINE_EQUIVALENCE) + continue; + + /* On ne prend que le lignes avec label */ + if(strlen(current_line->label_txt) == 0) + continue; + + /** Allocation de la structure Equivalence **/ + current_equivalence = (struct equivalence *) calloc(1,sizeof(struct equivalence)); + if(current_equivalence == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for structure equivalence"); + current_equivalence->name = strdup(current_line->label_txt); + current_equivalence->value = strdup(current_line->operand_txt); + if(current_equivalence->name == NULL || current_equivalence->value == NULL) + { + mem_free_equivalence(current_equivalence); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for 'name' from structure equivalence"); + } + current_equivalence->source_line = current_line; /* Cette equivalence vient d'un fichier source */ + + /* Déclaration de la structure */ + my_Memory(MEMORY_ADD_EQUIVALENCE,current_equivalence,NULL,current_omfsegment); + } + + /* Tri les Equivalence */ + my_Memory(MEMORY_SORT_EQUIVALENCE,NULL,NULL,current_omfsegment); + + /** On va repasser sur les équivalences pour résoudre celles dépendent d'autres équivalences **/ + modified = 1; + nb_modified = 0; + while(modified) + { + /* Init */ + modified= 0; + my_Memory(MEMORY_GET_EQUIVALENCE_NB,&nb_equivalence,NULL,current_omfsegment); + for(i=1; i<=nb_equivalence; i++) + { + my_Memory(MEMORY_GET_EQUIVALENCE,&i,¤t_equivalence,current_omfsegment); + + /** Découpe l'expression **/ + tab_element = DecodeOperandeAsElementTable(current_equivalence->value,&nb_element,SEPARATOR_REPLACE_LABEL,current_equivalence->source_line); + if(tab_element == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for 'tab_element' table"); + + /** On passe en revue les valeurs **/ + for(j=0,param->buffer_operand[0]='\0'; jbuffer_operand,"{"); + strcat(param->buffer_operand,replace_equivalence->value); /* Equivalence */ + strcat(param->buffer_operand,"}"); + + /* La valeur a été modifiée */ + modified = 1; + } + else + strcat(param->buffer_operand,tab_element[j]); + } + + /* Libération mémoire */ + mem_free_table(nb_element,tab_element); + + /** Si la valeur a été modifiée, on la remplace **/ + if(modified == 1) + { + new_value = strdup(param->buffer_operand); + if(new_value == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory to replace an Equivalence"); + + /* Libère l'ancienne */ + free(current_equivalence->value); + + /* Positionne la nouvelle */ + current_equivalence->value = new_value; + } + } + + /* On se protège des récursivités sans fin */ + if(modified) + nb_modified++; + if(nb_modified > 10) + my_RaiseError(ERROR_RAISE,"Recursivity detected in Equivalence replacement"); + } + + /* OK */ + return(0); +} + + +/******************************************************************/ +/* BuildExternalTable() : Construction des tables des External. */ +/******************************************************************/ +int BuildExternalTable(struct omf_segment *current_omfsegment) +{ + struct external *current_external; + struct source_file *first_file; + struct source_line *current_line; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Récupère le fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /* Init */ + my_Memory(MEMORY_FREE_EXTERNAL,NULL,NULL,current_omfsegment); + + /** Passe toutes les lignes en revue **/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes non valides */ + if(current_line->is_valid == 0) + continue; + + /* On ne prend que les External */ + if(current_line->type != LINE_EXTERNAL) + continue; + + /** Allocation de la structure External **/ + current_external = (struct external *) calloc(1,sizeof(struct external)); + if(current_external == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for structure external"); + current_external->name = strdup(current_line->label_txt); + if(current_external->name == NULL) + { + mem_free_external(current_external); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for 'name' from structure external"); + } + current_external->source_line = current_line; + + /* Déclaration de la structure */ + my_Memory(MEMORY_ADD_EXTERNAL,current_external,NULL,current_omfsegment); + } + + /* Tri les External */ + my_Memory(MEMORY_SORT_EXTERNAL,NULL,NULL,current_omfsegment); + + /* OK */ + return(0); +} + + +/*****************************************************************/ +/* CheckForDuplicatedLabel() : Recherche les Labels en double. */ +/*****************************************************************/ +int CheckForDuplicatedLabel(struct omf_segment *current_omfsegment) +{ + int i, nb_label, nb_equivalence, nb_error; + struct label *previous_label; + struct label *current_label; + struct equivalence *previous_equivalence; + struct equivalence *current_equivalence; + + /* Init */ + nb_error = 0; + + /** Recherche de doublons dans les Labels **/ + previous_label = NULL; + my_Memory(MEMORY_GET_LABEL_NB,&nb_label,NULL,current_omfsegment); + for(i=1; i<=nb_label; i++) + { + my_Memory(MEMORY_GET_LABEL,&i,¤t_label,current_omfsegment); + if(previous_label != NULL && current_label != NULL) + if(!strcmp(previous_label->name,current_label->name)) + { + printf(" => [Error] Found label name '%s' in both source files '%s' (line %d) and '%s' (line %d).\n",current_label->name, + previous_label->line->file->file_name, previous_label->line->file_line_number, + current_label->line->file->file_name, current_label->line->file_line_number); + nb_error++; + } + + previous_label = current_label; + } + + /** Recherche de doublons dans les Equivalence (mais pas dans les variables) **/ + previous_equivalence = NULL; + my_Memory(MEMORY_GET_EQUIVALENCE_NB,&nb_equivalence,NULL,current_omfsegment); + for(i=1; i<=nb_equivalence; i++) + { + my_Memory(MEMORY_GET_EQUIVALENCE,&i,¤t_equivalence,current_omfsegment); + if(previous_equivalence != NULL && current_equivalence != NULL) + if(!strcmp(previous_equivalence->name,current_equivalence->name)) + { + printf(" => [Error] Found label equivalence '%s' in both source files '%s' (line %d) and '%s' (line %d).\n",current_equivalence->name, + previous_equivalence->source_line->file->file_name, previous_equivalence->source_line->file_line_number, + current_equivalence->source_line->file->file_name, current_equivalence->source_line->file_line_number); + nb_error++; + } + + previous_equivalence = current_equivalence; + } + + /** Recherche de doublons entre les Label et les Equivalence **/ + for(i=1; i<=nb_equivalence; i++) + { + my_Memory(MEMORY_GET_EQUIVALENCE,&i,¤t_equivalence,current_omfsegment); + + /* Recherche un Label portant le même nom */ + my_Memory(MEMORY_SEARCH_LABEL,current_equivalence->name,¤t_label,current_omfsegment); + if(current_label != NULL) + { + printf(" => [Error] Found equivalence and label '%s' in both source files '%s' (line %d) and '%s' (line %d).\n",current_equivalence->name, + current_equivalence->source_line->file->file_name,current_equivalence->source_line->file_line_number, + current_label->line->file->file_name,current_label->line->file_line_number); + nb_error++; + } + } + + /* OK */ + return(nb_error); +} + + +/***************************************************************************/ +/* ProcessAllLocalLabel() : On remplace les labels locaux par des unid_. */ +/***************************************************************************/ +int ProcessAllLocalLabel(struct omf_segment *current_omfsegment) +{ + int i, error, nb_macro; + struct source_file *first_file; + struct source_line *current_line; + struct source_line *last_line = NULL; + struct macro *current_macro; + + /* Récupère le fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /** On traite les lignes du Source **/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + if(current_line->next == NULL) + last_line = current_line; + error = ProcessSourceLineLocalLabel(first_file->first_line,last_line,current_omfsegment); + + /** On traite les Macros **/ + my_Memory(MEMORY_GET_MACRO_NB,&nb_macro,NULL,current_omfsegment); + for(i=1; i<=nb_macro; i++) + { + my_Memory(MEMORY_GET_MACRO,&i,¤t_macro,current_omfsegment); + + /* Traite les lignes de cette Macro */ + error = ProcessMacroLineLocalLabel(current_macro->first_line,current_macro->last_line,current_macro,current_omfsegment); + } + + /* OK */ + return(0); +} + + +/*******************************************************************************************************/ +/* ProcessSourceLineLocalLabel() : On remplace les labels locaux par des unid_ des lignes du Source. */ +/*******************************************************************************************************/ +static int ProcessSourceLineLocalLabel(struct source_line *first_line, struct source_line *last_line, struct omf_segment *current_omfsegment) +{ + struct source_line *current_line; + struct source_line *other_line; + struct source_line *begin_global_line; + struct source_line *end_global_line; + struct source_line *replace_line; + int found, nb_local; + char *new_label; + char *new_operand; + char previous_label[256]; + char unique_label[256]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /*************************************************************************************/ + /** Si un Label :Local n'existe qu'en 1 seul exemplaire, on va le globaliser _Local **/ + /*************************************************************************************/ + for(current_line=first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes commentaires / celles sans labels / Label autres que :Label */ + if(current_line->type == LINE_COMMENT || current_line->is_valid == 0) + continue; + if(strlen(current_line->label_txt) == 0) + continue; + if(current_line->label_txt[0] != ':') + continue; + + /** Ce Label est t'il unique ? **/ + for(found=0,other_line=first_line; other_line; other_line=other_line->next) + { + /* On ignore les lignes commentaires / celles sans labels / Label autres que :Label */ + if(other_line->type == LINE_COMMENT || other_line->is_valid == 0) + continue; + if(strlen(other_line->label_txt) == 0) + continue; + if(other_line->label_txt[0] != ':') + continue; + if(other_line == current_line) + continue; + + /* Compare le Label */ + if(!strcmp(current_line->label_txt,other_line->label_txt)) + { + found = 1; + break; + } + } + + /** Il est unique, on va essayer de trouver un nom autre que oz_unid... **/ + if(found == 0) + { + /* On remplace le : par un _ */ + strcpy(unique_label,current_line->label_txt); + unique_label[0] = '_'; + + /* Ce _Label est t'il unique ? */ + for(found=0,other_line=first_line; other_line; other_line=other_line->next) + { + /* On ignore les lignes commentaires / celles sans labels / Label autres que :Label */ + if(other_line->type == LINE_COMMENT || other_line->is_valid == 0) + continue; + if(strlen(other_line->label_txt) == 0) + continue; + + /* Compare le Label */ + if(!strcmp(unique_label,other_line->label_txt)) + { + found = 1; + break; + } + } + + /* Il est unique, on l'utilise pour remplacer */ + if(found == 0) + { + /* Remplace :Label par _Label dans tout le fichier */ + strcpy(previous_label,current_line->label_txt); + for(other_line=first_line; other_line; other_line=other_line->next) + { + /* On remplace dans le label */ + if(!strcmp(other_line->label_txt,previous_label)) + { + other_line->label_txt[0] = '_'; + other_line->was_local_label = 1; /* Ce label a été un label local */ + } + + /** Remplace le Label dans l'Operand **/ + if(other_line->type == LINE_CODE || other_line->type == LINE_DATA || other_line->type == LINE_MACRO) + { + new_operand = ReplaceInOperand(other_line->operand_txt,previous_label,unique_label,SEPARATOR_REPLACE_LABEL,other_line); + if(new_operand != other_line->operand_txt) + { + free(other_line->operand_txt); + other_line->operand_txt = new_operand; + } + } + } + } + } + } + + /******************************************/ + /** On recherche le premier Label global **/ + /******************************************/ + for(begin_global_line=first_line; begin_global_line; begin_global_line=begin_global_line->next) + { + /* On ignore les lignes commentaires / celles sans labels / Celles avec des labels Variable ] */ + if(begin_global_line->type == LINE_COMMENT || begin_global_line->is_valid == 0) + continue; + if(strlen(begin_global_line->label_txt) == 0) + continue; + if(begin_global_line->label_txt[0] == ']') + continue; + if(begin_global_line->was_local_label == 1) + continue; + + /* Erreur : On ne peut pas commencer son source par un Label Local */ + if(begin_global_line->label_txt[0] == ':') + { + printf(" => [Error] Wrong Local Label : '%s' in file '%s' (line %d).\n",begin_global_line->data,begin_global_line->file->file_name,begin_global_line->file_line_number); + return(1); + } + + /* On est sur le 1er Label global */ + break; + } + + /* Aucun Label global dans le source => On prend le début du fichier comme référence */ + if(begin_global_line == NULL) + begin_global_line = first_line; + + /**************************************************************/ + /** On traite les Label locaux situés entre 2 labels globaux **/ + /**************************************************************/ + while(begin_global_line) + { + /* Recherche le label global suivant */ + for(nb_local=0,end_global_line = begin_global_line->next; end_global_line; end_global_line=end_global_line->next) + { + /* On saute */ + if(end_global_line->type == LINE_COMMENT || end_global_line->is_valid == 0) + continue; + if(strlen(end_global_line->label_txt) == 0) + continue; + if(end_global_line->label_txt[0] == ']') + continue; + if(end_global_line->was_local_label == 1) + continue; + + /* Comptabilise */ + if(end_global_line->label_txt[0] == ':') + { + nb_local++; + continue; + } + + /* Nouveau label global */ + break; + } + + /** Pas de Label Global => On prend la dernière ligne du Source **/ + if(end_global_line == NULL) + end_global_line = last_line; + + /** On a fini **/ + if(nb_local == 0 && end_global_line == last_line) + return(0); + + /** Aucun label local dans l'intervalle, on va au suivant **/ + if(nb_local == 0 && end_global_line != NULL) + { + begin_global_line = end_global_line; + continue; + } + + /** il y a du label local dans l'intervalle, on traite **/ + if(nb_local > 0) + { + /** On va passer toutes les lignes de l'intervalle en revue pour y corriger tous les labels locaux **/ + for(current_line=begin_global_line; current_line; current_line=current_line->next) + { + /* Saute les lignes non valides */ + if(current_line->is_valid == 0) + continue; + + /** On recherche un Label local **/ + if(current_line->label_txt[0] == ':') + { + /* Création d'un label unique */ + GetUNID(unique_label); + + /** On effectue le remplacement dans tout l'intervalle **/ + for(replace_line=begin_global_line; replace_line; replace_line=replace_line->next) + { + /** Remplace le Label dans l'Operand **/ + if(replace_line->type == LINE_CODE || replace_line->type == LINE_DATA || replace_line->type == LINE_MACRO) + { + new_operand = ReplaceInOperand(replace_line->operand_txt,current_line->label_txt,unique_label,SEPARATOR_REPLACE_LABEL,replace_line); + if(new_operand != replace_line->operand_txt) + { + free(replace_line->operand_txt); + replace_line->operand_txt = new_operand; + } + } + + /* Fin de zone */ + if(replace_line == end_global_line) + break; + } + + /** Remplace le label de la ligne **/ + new_label = strdup(unique_label); + if(new_label == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for new local label"); + free(current_line->label_txt); + current_line->label_txt = new_label; + current_line->was_local_label = 1; /* Ce label a été un label local */ + } + + /* Fin de la zone */ + if(current_line == end_global_line) + break; + } + } + } + + /* OK */ + return(0); +} + + +/*******************************************************************************************************/ +/* ProcessMacroLineLocalLabel() : On remplace les labels locaux par des unid_ des lignes des Macros. */ +/*******************************************************************************************************/ +static int ProcessMacroLineLocalLabel(struct macro_line *first_line, struct macro_line *last_line, struct macro *current_macro, struct omf_segment *current_omfsegment) +{ + struct macro_line *current_line; + struct macro_line *begin_global_line; + struct macro_line *end_global_line; + struct macro_line *replace_line; + int nb_local; + char *new_label; + char *new_operand; + char unique_label[256]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /** On recherche le premier Label global **/ + for(begin_global_line=first_line; begin_global_line; begin_global_line=begin_global_line->next) + { + /* On ignore les lignes commentaires / celles sans labels / Celles avec des labels Variable ] */ + if(strlen(begin_global_line->label) == 0) + continue; + if(begin_global_line->label[0] == ']') + continue; + + /* On est sur le 1er Label global */ + break; + } + + /* Aucun Label global dans le source => On prend la 1ère ligne comme référence */ + if(begin_global_line == NULL) + begin_global_line = first_line; + + /** On traite les Label locaux situées entre 2 labels globaux **/ + while(begin_global_line) + { + /* Recherche le label global suivant */ + for(nb_local=0,end_global_line = begin_global_line->next; end_global_line; end_global_line=end_global_line->next) + { + /* On saute */ + if(strlen(end_global_line->label) == 0) + continue; + if(end_global_line->label[0] == ']') + continue; + + /* Comptabilise */ + if(end_global_line->label[0] == ':') + { + nb_local++; + continue; + } + + /* Nouveau label global */ + break; + } + + /* On a atteind la fin sans rencontrer de Label Global */ + if(end_global_line == NULL) + end_global_line = last_line; + + /** On a fini **/ + if(nb_local == 0 && end_global_line == last_line) + return(0); + + /** Aucun label local dans l'intervalle, on va au suivant **/ + if(nb_local == 0 && end_global_line != NULL) + { + begin_global_line = end_global_line; + continue; + } + + /** il y a du label local dans l'intervalle, on traite **/ + if(nb_local > 0) + { + /** On va passer toutes les lignes de l'intervalle en revue pour y corriger tous les labels locaux **/ + for(current_line=begin_global_line; current_line; current_line=current_line->next) + { + /** On recherche un Label local **/ + if(current_line->label[0] == ':') + { + /* Création d'un label unique */ + GetUNID(unique_label); + + /** On effectue le remplacement dans tout l'intervalle **/ + for(replace_line=begin_global_line; replace_line; replace_line=replace_line->next) + { + /** Remplace le Label dans l'Operand **/ + new_operand = ReplaceInOperand(replace_line->operand,current_line->label,unique_label,SEPARATOR_REPLACE_LABEL,NULL); + if(new_operand != replace_line->operand) + { + free(replace_line->operand); + replace_line->operand = new_operand; + } + + /* Fin de zone */ + if(replace_line == end_global_line) + break; + } + + /** Remplace le label de la ligne **/ + new_label = strdup(unique_label); + if(new_label == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for new local label in Macro"); + free(current_line->label); + current_line->label = new_label; + } + + /* Fin de la zone */ + if(current_line == end_global_line) + break; + } + } + } + + /* OK */ + return(0); +} + + +/*********************************************************************************/ +/* ProcessAllVariableLabel() : On remplace les ]labels Variable par des unid_. */ +/*********************************************************************************/ +int ProcessAllVariableLabel(struct omf_segment *current_omfsegment) +{ + int i, error, nb_macro; + struct source_file *first_file; + struct source_line *current_line; + struct source_line *last_line = NULL; + struct macro *current_macro; + + /* Récupère le fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /** On traite les lignes du Source **/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + if(current_line->next == NULL) + last_line = current_line; + error = ProcessSourceLineVariableLabel(first_file->first_line,last_line,current_omfsegment); + + /** On traite les Macros **/ + my_Memory(MEMORY_GET_MACRO_NB,&nb_macro,NULL,current_omfsegment); + for(i=1; i<=nb_macro; i++) + { + my_Memory(MEMORY_GET_MACRO,&i,¤t_macro,current_omfsegment); + + /** Traite les lignes de cette Macro **/ + error = ProcessMacroLineVariableLabel(current_macro->first_line,current_macro->last_line,current_macro,current_omfsegment); + } + + /* OK */ + return(0); +} + + +/**************************************************************************************************/ +/* ProcessSourceLineVariableLabel() : On remplace les ]labels variable du source par des unid_. */ +/**************************************************************************************************/ +int ProcessSourceLineVariableLabel(struct source_line *first_line, struct source_line *last_line, struct omf_segment *current_omfsegment) +{ + struct source_line *replace_line; + struct source_line *begin_variable_line; + struct source_line *end_variable_line; + int use_address; + char *new_label; + char *new_operand; + char unique_label[256]; + char buffer_error[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /*** Traite tous les Labels Variable ]label ***/ + for(begin_variable_line=first_line; begin_variable_line; begin_variable_line=begin_variable_line->next) + { + /* On ignore les lignes commentaires / celles sans labels */ + if(begin_variable_line->type == LINE_COMMENT || strlen(begin_variable_line->label_txt) == 0 || begin_variable_line->is_valid == 0) + continue; + if(begin_variable_line->type == LINE_VARIABLE) + { + /* Il faut différencer une vrai Equivalence d'un label ]LP = * */ + if(strchr(begin_variable_line->operand_txt,'*') == NULL) + continue; + + /** Peut t'on détecter un * utilisé comme valeur ? **/ + use_address = UseCurrentAddress(begin_variable_line->operand_txt,&buffer_error[0],begin_variable_line); + if(strlen(buffer_error) > 0) + { + printf(" Error : Impossible to analyze Operand '%s' in source file '%s' (line %d) : %s.\n", + begin_variable_line->operand_txt,begin_variable_line->file->file_name,begin_variable_line->file_line_number,buffer_error); + return(1); + } + if(use_address == 0) + continue; + } + + /** Début de la zone de recherche **/ + if(begin_variable_line->label_txt[0] == ']') + { + /** Cherche la fin de la zone de recherche = Autre Label variable avec le même nom **/ + for(end_variable_line=begin_variable_line->next; end_variable_line; end_variable_line=end_variable_line->next) + { + /* On ignore les lignes commentaires / celles sans labels */ + if(end_variable_line->type == LINE_COMMENT || strlen(end_variable_line->label_txt) == 0 || end_variable_line->is_valid == 0) + continue; + + /* On recherche le même Label (Case sensitive) */ + if(!strcmp(begin_variable_line->label_txt,end_variable_line->label_txt)) + break; + } + + /* Création d'un label unique */ + GetUNID(unique_label); + + /** On remplace sur la zone **/ + for(replace_line=begin_variable_line; replace_line != end_variable_line; replace_line=replace_line->next) + { + /* On ne traite pas les lignes invalides */ + if(replace_line->is_valid == 0) + continue; + + /** Remplace le Label dans l'Operand **/ + new_operand = ReplaceInOperand(replace_line->operand_txt,begin_variable_line->label_txt,unique_label,SEPARATOR_REPLACE_VARIABLE,replace_line); + if(new_operand != replace_line->operand_txt) + { + free(replace_line->operand_txt); + replace_line->operand_txt = new_operand; + } + } + + /** Remplace le label de la ligne **/ + new_label = strdup(unique_label); + if(new_label == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for new variable label"); + free(begin_variable_line->label_txt); + begin_variable_line->label_txt = new_label; + } + } + + /* OK */ + return(0); +} + + +/****************************************************************************************************/ +/* ProcessMacroLineVariableLabel() : On remplace les ]labels variable d'une Macro par des unid_. */ +/****************************************************************************************************/ +int ProcessMacroLineVariableLabel(struct macro_line *first_line, struct macro_line *last_line, struct macro *current_macro, struct omf_segment *current_omfsegment) +{ + struct macro_line *replace_line; + struct macro_line *begin_variable_line; + struct macro_line *end_variable_line; + int use_address; + char *new_label; + char *new_operand; + char buffer_error[1024]; + char unique_label[256]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /*** Traite tous les Labels Variable ]label ***/ + for(begin_variable_line=first_line; begin_variable_line; begin_variable_line=begin_variable_line->next) + { + /* On ignore les lignes commentaires / celles sans labels */ + if(strlen(begin_variable_line->label) == 0) + continue; + if(!strcmp(begin_variable_line->opcode,"=")) + { + /* Il faut différencer une vrai Equivalence d'un label ]LP = * */ + if(strchr(begin_variable_line->operand,'*') == NULL) + continue; + + /** Peut t'on détecter un * utilisé comme valeur ? **/ + use_address = UseCurrentAddress(begin_variable_line->operand,&buffer_error[0],NULL); + if(strlen(buffer_error) > 0) + { + printf(" Error : Impossible to analyze Operand '%s' in Macro %s : %s.\n",begin_variable_line->operand,current_macro->name,buffer_error); + return(1); + } + if(use_address == 0) + continue; + } + + /** Début de la zone de recherche **/ + if(begin_variable_line->label[0] == ']') + { + /** Cherche la fin de la zone de recherche = Autre Label variable avec le même nom **/ + for(end_variable_line=begin_variable_line->next; end_variable_line; end_variable_line=end_variable_line->next) + { + /* On ignore les lignes commentaires / celles sans labels */ + if(strlen(end_variable_line->label) == 0) + continue; + + /* On recherche le même Label (Case sensitive) */ + if(!strcmp(begin_variable_line->label,end_variable_line->label)) + break; + } + + /* Création d'un label unique */ + GetUNID(unique_label); + + /** On remplace sur la zone **/ + for(replace_line=begin_variable_line; replace_line != end_variable_line; replace_line=replace_line->next) + { + /** Remplace le Label dans l'Operand **/ + new_operand = ReplaceInOperand(replace_line->operand,begin_variable_line->label,unique_label,SEPARATOR_REPLACE_VARIABLE,NULL); + if(new_operand != replace_line->operand) + { + free(replace_line->operand); + replace_line->operand = new_operand; + } + } + + /** Remplace le label de la ligne **/ + new_label = strdup(unique_label); + if(new_label == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for new variable label in Macro"); + free(begin_variable_line->label); + begin_variable_line->label = new_label; + } + } + + /* OK */ + return(0); +} + + +/*******************************************************/ +/* ProcessEquivalence() : Remplace les Equivalences. */ +/*******************************************************/ +int ProcessEquivalence(struct omf_segment *current_omfsegment) +{ + struct source_file *first_file; + struct source_line *current_line; + int nb_modified; + + /* Init */ + nb_modified = 0; + + /* Récupère le fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /*** Traite tous les Operands pouvant contenir des Equivalence ***/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes non valides */ + if(current_line->is_valid == 0) + continue; + + /* On ignore les lignes commentaires / celles sans labels */ + if(current_line->type == LINE_COMMENT || current_line->type == LINE_EMPTY || current_line->type == LINE_GLOBAL || strlen(current_line->operand_txt) == 0) + continue; + + /* On ne fait pas de remplacement sur les lignes de Data HEX */ + if(current_line->type == LINE_DATA && !my_stricmp(current_line->opcode_txt,"HEX")) + continue; + + /* Remplace les Equivalences sur la Ligne */ + nb_modified += ProcessLineEquivalence(current_line,current_omfsegment); + } + + /* OK */ + return(0); +} + + +/************************************************************************/ +/* ProcessLineEquivalence() : Remplace les équivalences pour 1 ligne. */ +/************************************************************************/ +int ProcessLineEquivalence(struct source_line *current_line, struct omf_segment *current_omfsegment) +{ + int i, modified, nb_element, is_variable, is_label, is_hexa, nb_byte; + char **tab_element; + char *new_operand; + char variable_name[1024]; + struct equivalence *current_equivalence; + struct variable *current_variable; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + modified = 0; + + /** On va découper l'opérande en plusieurs éléments unitaires **/ + tab_element = DecodeOperandeAsElementTable(current_line->operand_txt,&nb_element,SEPARATOR_REPLACE_LABEL,current_line); + if(tab_element == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to decode Operand as element table"); + + /** On reconstruit la chaine en remplaçant les valeurs (case sensitive) **/ + for(i=0,param->buffer_operand[0]='\0'; i 0) + { + if(!strcmp(tab_element[i-1],"]")) + { + sprintf(variable_name,"]%s",tab_element[i]); + my_Memory(MEMORY_SEARCH_VARIABLE,variable_name,¤t_variable,current_omfsegment); + if(current_variable != NULL) + is_variable = 1; + else + { + /* On regarde s'il n'existerait pas un label local portant ce nom */ + if(IsLocalLabel(variable_name,current_omfsegment)) + is_label = 1; + } + } + else if(!strcmp(tab_element[i-1],"$")) + { + /* Peut t'on interpretter $variable comme un nombre Hexa ? */ + sprintf(variable_name,"$%s",tab_element[i]); + if(IsHexaDecimal(variable_name,&nb_byte)) + is_hexa = 1; + } + } + + /* On ne va pas remplacer si c'est finalement une Variable / Label / une forme hexa */ + if(is_variable || is_label || is_hexa) + strcat(param->buffer_operand,tab_element[i]); /* Variable */ + else + { + strcat(param->buffer_operand,"{"); + strcat(param->buffer_operand,current_equivalence->value); /* Equivalence */ + strcat(param->buffer_operand,"}"); + } + } + else + strcat(param->buffer_operand,tab_element[i]); + } + + /* Libération mémoire du tableau de valeurs */ + mem_free_table(nb_element,tab_element); + + /** Remplace l'Operande (si qqchose a été changé) **/ + if(strcmp(param->buffer_operand,current_line->operand_txt)) + { + /* Nouvelle chaine */ + new_operand = strdup(param->buffer_operand); + if(new_operand == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory to replace an Equivalence"); + + /* Libère l'ancienne */ + free(current_line->operand_txt); + + /* ositionne la nouvelle */ + current_line->operand_txt = new_operand; + + /* Modification */ + modified = 1; + } + + /* At t'on modifié la ligne ? */ + return(modified); +} + + +/**********************************************/ +/* IsLocalLabel() : Est-ce un label local ? */ +/**********************************************/ +static int IsLocalLabel(char *label_name, struct omf_segment *current_omfsegment) +{ + struct source_line *current_line; + struct source_file *first_file; + + /* Récupère le fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /** Passe toutes les lignes en revue **/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ne prend pas les Variables dans les Macro */ + if(current_line->type != LINE_CODE && current_line->type_aux != LINE_DATA) + continue; + + /* Recherche le ]label */ + if(strcmp(current_line->label_txt,label_name)) + return(1); + } + + /* Pas trouvé */ + return(0); +} + + +/*******************************************************************/ +/* BuildVariableTable() : Construction des tables des Variables. */ +/*******************************************************************/ +int BuildVariableTable(struct omf_segment *current_omfsegment) +{ + struct variable *current_variable; + struct source_line *current_line; + struct source_file *first_file; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Récupère le fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /* Init */ + my_Memory(MEMORY_SORT_VARIABLE,NULL,NULL,current_omfsegment); + + /** Passe toutes les lignes en revue **/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes non valides */ + if(current_line->is_valid == 0) + continue; + + /* On ne prend pas les Variables dans les Macro */ + if(current_line->type == LINE_DIRECTIVE && current_line->type_aux == LINE_MACRO_DEF) + continue; + + /* On ne prend que les lignes avec label */ + if(strlen(current_line->label_txt) == 0) + continue; + + /* On ne prend que les Variables ]XX = */ + if(current_line->type != LINE_VARIABLE) + continue; + + /** Recherche d'une variable de même nom déjà existante **/ + my_Memory(MEMORY_SEARCH_VARIABLE,current_line->label_txt,¤t_variable,current_omfsegment); + + /** Allocation d'une nouvelle structure Variable **/ + if(current_variable == NULL) + { + current_variable = (struct variable *) calloc(1,sizeof(struct variable)); + if(current_variable == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for structure variable"); + current_variable->name = strdup(current_line->label_txt); + if(current_variable->name == NULL) + { + free(current_variable); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for 'name' from structure variable"); + } + + /* Initialisation à 0 */ + current_variable->value = 0; + + /* Format $, #$ */ + if(current_line->operand_txt[0] == '$') + current_variable->is_dollar = 1; + else if(current_line->operand_txt[0] == '#') + { + if(current_line->operand_txt[1] == '$') + current_variable->is_pound_dollar = 1; + else + current_variable->is_pound = 1; + } + + /* Déclaration de la structure */ + my_Memory(MEMORY_ADD_VARIABLE,current_variable,NULL,current_omfsegment); + } + + /* On fait pointer cette ligne vers la variable */ + current_line->variable = current_variable; + } + + /* Tri les Variables */ + my_Memory(MEMORY_SORT_VARIABLE,NULL,NULL,current_omfsegment); + + /* OK */ + return(0); +} + + +/*******************************************************************/ +/* BuildReferenceTable() : Construction des tables de référence. */ +/*******************************************************************/ +void BuildReferenceTable(struct omf_segment *current_omfsegment) +{ + int i; + + /** Opcode **/ + for(i=0; opcode_list[i]!=NULL; i++) + my_Memory(MEMORY_ADD_OPCODE,opcode_list[i],NULL,current_omfsegment); + my_Memory(MEMORY_SORT_OPCODE,NULL,NULL,current_omfsegment); + + /** Data **/ + for(i=0; data_list[i]!=NULL; i++) + my_Memory(MEMORY_ADD_DATA,data_list[i],NULL,current_omfsegment); + my_Memory(MEMORY_SORT_DATA,NULL,NULL,current_omfsegment); + + /** Directive **/ + for(i=0; directive_list[i]!=NULL; i++) + my_Memory(MEMORY_ADD_DIRECTIVE,directive_list[i],NULL,current_omfsegment); + my_Memory(MEMORY_SORT_DIRECTIVE,NULL,NULL,current_omfsegment); + + /** DirectiveEqu **/ + for(i=0; equivalence_list[i]!=NULL; i++) + my_Memory(MEMORY_ADD_DIREQU,equivalence_list[i],NULL,current_omfsegment); + my_Memory(MEMORY_SORT_DIREQU,NULL,NULL,current_omfsegment); +} + + +/***********************************************************************/ +/* ProcessMXDirective() : On va reconnaitres les MX de chaque ligne. */ +/***********************************************************************/ +int ProcessMXDirective(struct omf_segment *current_omfsegment) +{ + BYTE byte_count, bit_shift; + WORD offset_reference; + DWORD address_long; + int is_reloc; + int64_t value; + char m, x; + struct source_file *first_file; + struct source_line *current_line; + struct external *current_external; + char buffer_error[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + m = '1'; + x = '1'; + + /* Récupère le 1er fichier source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + if(first_file == NULL) + return(0); + + /*** Passe en revue toutes les lignes ***/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes invalides */ + if(current_line->is_valid == 0) + continue; + + /** Nouvelle valeur de M et X **/ + if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"MX")) + { + /* Récupère la valeur */ + value = EvalExpressionAsInteger(current_line->operand_txt,buffer_error,current_line,current_line->nb_byte-1,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Impossible to evaluate MX value '%s' (line %d from file '%s') : %s",current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + if(value < 0 || value > 3) + { + sprintf(param->buffer_error,"Bad value '%d' for MX directive '%s' (line %d from file '%s') : %s",(int)value,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Décode M et X */ + m = ((value & 0x02) == 0) ? '0' : '1'; + x = ((value & 0x01) == 0) ? '0' : '1'; + + /** On place les valeurs MX sur la ligne **/ + current_line->m[0] = m; + current_line->x[0] = x; + } + else if(current_line->type == LINE_CODE && (!my_stricmp(current_line->opcode_txt,"REP") || !my_stricmp(current_line->opcode_txt,"SEP"))) + { + /* Récupère la valeur */ + value = EvalExpressionAsInteger(current_line->operand_txt,buffer_error,current_line,1,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Impossible to evaluate %s value '%s' (line %d from file '%s') : %s",current_line->opcode_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + if(value < 0 || value > 256) + { + sprintf(param->buffer_error,"Bad value '%d' for %s '%s' (line %d from file '%s') : %s",(int)value,current_line->opcode_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Décode M et X */ + if(!my_stricmp(current_line->opcode_txt,"REP")) + { + m = ((value & 0x20) == 0) ? m : '0'; + x = ((value & 0x10) == 0) ? x : '0'; + } + else /* SEP */ + { + m = ((value & 0x20) == 0) ? m : '1'; + x = ((value & 0x10) == 0) ? x : '1'; + } + + /** On place les valeurs MX sur la ligne **/ + current_line->m[0] = m; + current_line->x[0] = x; + } + else if(current_line->type == LINE_CODE && !my_stricmp(current_line->opcode_txt,"SEC") && current_line->next != NULL) + { + /** On place les valeurs MX sur la ligne **/ + current_line->m[0] = m; + current_line->x[0] = x; + + /* On a un XCE qui suit => 8 bit */ + if(current_line->next->is_valid == 1 && current_line->next->type == LINE_CODE && !my_stricmp(current_line->next->opcode_txt,"XCE")) + { + m = '1'; + x = '1'; + } + } + else + { + /** On place les valeurs MX sur la ligne **/ + current_line->m[0] = m; + current_line->x[0] = x; + } + } + + /* OK */ + return(0); +} + + +/**********************************************************************/ +/* EvaluateVariableLine() : Evaluation de la variable sur sa ligne. */ +/**********************************************************************/ +int EvaluateVariableLine(struct source_line *current_line, struct omf_segment *current_omfsegment) +{ + int64_t value; + int is_reloc; + BYTE byte_count, bit_shift; + WORD offset_reference; + DWORD address_long; + char buffer_error[1024] = ""; + struct variable *current_variable; + struct external *current_external; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /** On va rechercher la variable **/ + my_Memory(MEMORY_SEARCH_VARIABLE,current_line->label_txt,¤t_variable,current_omfsegment); + if(current_variable == NULL) + return(0); + + /** On va évaluer la variable **/ + value = EvalExpressionAsInteger(current_line->operand_txt,&buffer_error[0],current_line,4,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Impossible to evaluate Variable '%s' value '%s' (line %d, file '%s') : %s", + current_variable->name,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Stocke la valeur */ + current_variable->value = value; + + /* OK */ + return(0); +} + + +/***********************************************************************/ +/* ComputeLineAddress() : Détermine les adresses des lignes valides. */ +/***********************************************************************/ +int ComputeLineAddress(struct omf_segment *current_omfsegment, struct omf_project *current_omfproject) +{ + BYTE byte_count, bit_shift; + WORD offset_reference; + DWORD address_long; + int64_t new_address_64, dum_address_64; + int line_number, current_address, global_address, new_address, dum_address, nb_byte, has_previous_label, is_reloc, is_first_org, is_fix_address; + int current_bank, global_bank, new_bank, dum_bank; + struct source_file *first_file; + struct source_line *current_line; + struct external *current_external; + char *next_sep; + char operand[1024]; + char buffer_error[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + if(current_omfproject->is_omf == 1) + { + /* Le code OMF est relogeable */ + current_bank = 0; + current_address = 0x0000; + current_omfsegment->is_omf = 1; + is_fix_address = 0; + } + else if(current_omfproject->is_single_binary == 1) + { + /* L'adresse ORG est transmise de Segment en Segment (qui s'enchainent) */ + current_bank = (current_omfsegment->org_address >> 16); + current_address = 0xFFFF & current_omfsegment->org_address; + is_fix_address = 0; + } + else + { + current_bank = 0; + current_address = 0x8000; + is_fix_address = 1; + } + global_bank = current_bank; + global_address = current_address; + has_previous_label = 0; + line_number = 1; + is_first_org = 1; + + /* Récupère le 1er fichier source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + if(first_file == NULL) + return(0); + + /** Numérote toutes les lignes **/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes invalides */ + if(current_line->is_valid == 0) + continue; + + /* Numéro de la ligne du Projet */ + current_line->line_number = line_number++; + } + + /** Recherche un REL si on ne sait pas encore quel est le type de projet **/ + if(current_omfproject->is_omf == 0 && current_omfproject->is_single_binary == 0 && current_omfproject->is_multi_fixed == 0) + { + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes invalides */ + if(current_line->is_valid == 0) + continue; + + /** On cherche le 1er REL **/ + if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"REL")) + { + /* On ne doit rien y avoir avant */ + if(has_previous_label == 1) + { + sprintf(param->buffer_error,"Error : The REL directive should be located at the top of the file (line %d, file '%s')",current_line->file_line_number,current_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* L'assemblage va commence en $0000 */ + current_bank = 0; + current_address = 0x0000; + global_bank = 0; + global_address = 0x0000; + + /* Le fichier est relogeable au format OMF */ + current_omfsegment->is_omf = 1; + current_omfproject->is_omf = 1; + is_fix_address = 0; + break; + } + else if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"USE")) + has_previous_label = 1; + else if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"PUT")) + has_previous_label = 1; + else if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"PUTBIN")) + has_previous_label = 1; + else if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"OBJ") && current_omfsegment->is_omf == 1) + { + /* Never Here */ + sprintf(param->buffer_error,"Error : The OBJ directive is not allowed with source code having already define a REL directive (line %d, file '%s')",current_line->file_line_number,current_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + else if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"ORG") && current_omfsegment->is_omf == 1) + { + /* Never Here */ + sprintf(param->buffer_error,"Error : The ORG directive is not allowed with source code having already define a REL directive (line %d, file '%s')",current_line->file_line_number,current_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + else if((current_line->type == LINE_CODE || current_line->type == LINE_DATA || current_line->type == LINE_MACRO || current_line->type == LINE_EMPTY || current_line->type == LINE_GLOBAL) && strlen(current_line->label_txt) > 0) + has_previous_label = 1; + } + } + + /*** Passe en revue toutes les lignes ***/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes non valides */ + if(current_line->is_valid == 0) + continue; + + /** Directive modifiant l'adresse : ORG+DUM **/ + if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"ORG")) + { + /** Org $Addr (pour les OMF et les SingleBinary, on a une zone [ORG $Addr - ORG] à adresse fixe) **/ + if(strlen(current_line->operand_txt) > 0) + { + /* Récupère la nouvelle addresse */ + new_address_64 = EvalExpressionAsInteger(current_line->operand_txt,&buffer_error[0],current_line,2,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Error : Impossible to evaluate ORG Address : '%s' (line %d, file '%s') : %s",current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + /* On ne conserve que 32 bit */ + new_address = (int) (0xFFFFFFFF & new_address_64); + + /* On reste dans les 64 KB */ + new_bank = new_address >> 16; + new_address = new_address & 0xFFFF; + + /* Nouvelle addresse */ + current_line->bank = current_bank; + current_line->address = current_address; + current_line->is_fix_address = is_fix_address; + current_line->global_bank = global_bank; /* Adresse sans tenir compte des [ORG $Addr ORG] */ + current_line->global_address = global_address; + current_bank = new_bank; + current_address = new_address; + + /* Le premier ORG nous sert à définir l'adresse globale (pour les binaires à adresse fixe) */ + if(is_first_org == 1 && current_omfproject->is_omf == 0 && current_omfproject->is_single_binary == 0) + { + global_bank = new_bank; + global_address = new_address; + is_first_org = 0; + } + + /* A partir de maintenant toutes les lignes sont en adresses Fixes => pas relogeable */ + is_fix_address = 1; + continue; + } + else /* ORG */ + { + /** On rétablit l'adresse du fichier global **/ + current_bank = global_bank; + current_address = global_address; + + /* A partir de maintenant toutes les lignes OMF / SingleBinary ne sont plus en adresses Fixes */ + if(current_omfproject->is_omf == 1 || current_omfproject->is_single_binary == 1) + is_fix_address = 0; + } + } + else if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"DUM")) + { + /* Récupère la nouvelle addresse */ + dum_address_64 = EvalExpressionAsInteger(current_line->operand_txt,&buffer_error[0],current_line,2,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Error : Impossible to evaluate DUM Address : '%s' (line %d, file '%s') : %s",current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + /* On ne conserve que 32 bit */ + dum_address = (int) (0xFFFFFFFF & dum_address_64); + + /* On reste dans les 64 KB */ + dum_bank = dum_address >> 16; + dum_address = 0xFFFF & dum_address; + } + + /* On met l'adresse courrante à la ligne */ + if(current_line->is_dum == 1) + { + current_line->bank = dum_bank; + current_line->address = dum_address; + current_line->is_fix_address = is_fix_address; + current_line->global_bank = global_bank; /* Adresse sans tenir compte des [ORG $Addr ORG] */ + current_line->global_address = global_address; + + /* On définit l'adresse suivante */ + if(current_line->nb_byte == 0xFFFF) + { + /* Cas particulier des lignes DS \ : Alignement sur le prochain $100 */ + nb_byte = 0x100 - (dum_address & 0x0000FF); + current_line->nb_byte = nb_byte; + dum_address += nb_byte; + } + else if(current_line->nb_byte == 0xFFFFF) + { + /** Cas particulier des lignes DS avec des Labels dedans : On essaye de ré-évaluer **/ + /* Isole l'expression indiquant la longueur */ + strcpy(operand,current_line->operand_txt); + next_sep = strchr(operand,','); + if(next_sep) + *next_sep = '\0'; + + /* Calcule l'expression */ + nb_byte = (int) EvalExpressionAsInteger(operand,&buffer_error[0],current_line,3,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Error : Impossible to evaluate DS data size : '%s' (line %d, file '%s') : %s",operand,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + if(nb_byte < 0) + { + sprintf(param->buffer_error,"Error : Evaluation of DS data size ends up as negative value (%d) : '%d' (line %d, file '%s')",nb_byte,operand,current_line->file_line_number,current_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* On a enfin la taille occupée par la ligne */ + current_line->nb_byte = nb_byte; + dum_address += nb_byte; + } + else + { + /* On saute de la taille de l'instruction */ + dum_address += current_line->nb_byte; + } + + /* Erreur : on dépasse 64 KB */ + if(dum_address > 0xFFFF) + { + sprintf(param->buffer_error,"Error : DUM Object code size > 64 KB (line %d, file '%s')",current_line->file_line_number,current_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + } + else + { + /* Adresse de la ligne */ + current_line->bank = current_bank; + current_line->address = current_address; + current_line->is_fix_address = is_fix_address; + current_line->global_bank = global_bank; /* Adresse sans tenir compte des [ORG $Addr ORG] */ + current_line->global_address = global_address; + + /* On définit l'adresse suivante */ + if(current_line->nb_byte == 0xFFFF) + { + /* Cas particulier des lignes DS \ : Alignement sur le prochain $100 */ + nb_byte = 0x100 - (current_address & 0x0000FF); + current_line->nb_byte = nb_byte; + current_address += nb_byte; + global_address += nb_byte; + } + else if(current_line->nb_byte == 0xFFFFF) + { + /** Cas particulier des lignes DS avec des Labels dedans : On essaye de ré-évaluer **/ + /* Isole l'expression indiquant la longueur */ + strcpy(operand,current_line->operand_txt); + next_sep = strchr(operand,','); + if(next_sep) + *next_sep = '\0'; + + /* Calcule l'expression */ + nb_byte = (int) EvalExpressionAsInteger(operand,&buffer_error[0],current_line,3,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Error : Impossible to evaluate DS data size : '%s' (line %d, file '%s') : %s",operand,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + if(nb_byte < 0) + { + sprintf(param->buffer_error,"Error : Evaluation of DS data size ends up as negative value (%d) : '%s' (line %d, file '%s')",nb_byte,operand,current_line->file_line_number,current_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* On a enfin la taille occupée par la ligne */ + current_line->nb_byte = nb_byte; + current_address += nb_byte; + global_address += nb_byte; + } + else if(current_line->nb_byte > 0) + { + /* On saute de la taille de l'instruction */ + current_address += current_line->nb_byte; + global_address += current_line->nb_byte; + } + + /* Erreur : on dépasse 64 KB */ + if(current_address > 0x10000) /* bug 0xFFFF */ + { + sprintf(param->buffer_error,"Error : Object code size > 64 KB (line %d, file '%s')",current_line->file_line_number,current_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + } + } + + /* OK */ + return(0); +} + + +/********************************************************************************/ +/* BuildRelocateAddress() : On signale une adresse comme devant être patchée. */ +/********************************************************************************/ +struct relocate_address *BuildRelocateAddress(BYTE ByteCnt, BYTE BitShiftCnt, WORD OffsetPatch, WORD OffsetReference, struct external *current_external, struct omf_segment *current_omfsegment) +{ + struct relocate_address *current_address; + struct relocate_address *next_address; + + /* Allocation mémoire */ + current_address = (struct relocate_address *) calloc(1,sizeof(struct relocate_address)); + if(current_address == NULL) + my_RaiseError(ERROR_RAISE,"Error : Can't allocate memory for relocate_address structure."); + + /* Remplissage */ + current_address->ByteCnt = ByteCnt; + current_address->BitShiftCnt = BitShiftCnt; + current_address->OffsetPatch = OffsetPatch; + current_address->OffsetReference = OffsetReference; + + /* Si on se référe à un label externe au Segment */ + current_address->external = current_external; + + /* Attache en triant les adresses OffsetPath */ + if(current_omfsegment->first_address == NULL) + { + current_omfsegment->first_address = current_address; + current_omfsegment->last_address = current_address; + } + else + { + /* Ajoute en 1ère position */ + if(current_address->OffsetPatch < current_omfsegment->first_address->OffsetPatch) + { + current_address->next = current_omfsegment->first_address; + current_omfsegment->first_address = current_address; + } + else if(current_address->OffsetPatch >= current_omfsegment->last_address->OffsetPatch) + { + /* Attache en dernière position */ + current_omfsegment->last_address->next = current_address; + current_omfsegment->last_address = current_address; + } + else + { + /* Attache au milieu */ + for(next_address=current_omfsegment->first_address; ; next_address=next_address->next) + if(next_address->next->OffsetPatch >= current_address->OffsetPatch) + { + current_address->next = next_address->next; + next_address->next = current_address; + break; + } + } + } + + /* Une addresse de plus */ + current_omfsegment->nb_address++; + + return(current_address); +} + + +/**************************************************************************/ +/* CheckForUnknownLine() : Recherche toutes les lignes non identifiées. */ +/**************************************************************************/ +int CheckForUnknownLine(struct omf_segment *current_omfsegment) +{ + int nb_error; + struct source_line *current_line; + struct source_file *first_file; + + /* Init */ + nb_error = 0; + + /* Récupère le fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /** Passe toutes les lignes en revue **/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes non valides */ + if(current_line->is_valid == 0) + continue; + + /* On ne prend pas les Label dans les Macro */ + if(current_line->type == LINE_UNKNOWN) + { + printf(" => [Error] Unkown line : '%s %s %s' in file '%s' (line %d).\n",current_line->label_txt,current_line->opcode_txt,current_line->operand_txt,current_line->file->file_name,current_line->file_line_number); + nb_error++; + } + } + + /* Renvoi le nombre d'erreur détectés */ + return(nb_error); +} + + +/*************************************************************/ +/* CheckForDumLine() : Vérifie toutes les lignes DUM-DEND. */ +/*************************************************************/ +int CheckForDumLine(struct omf_segment *current_omfsegment) +{ + struct source_file *first_file; + struct source_line *current_line; + struct source_line *dend_line; + + /* Récupère le fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /** Passe toutes les lignes en revue **/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes non valides */ + if(current_line->is_valid == 0) + continue; + + /* On va rechercher les zones DUM-DEND */ + if(current_line->type == LINE_DIRECTIVE && !my_stricmp(current_line->opcode_txt,"DUM")) + { + /* On vérifie la présence d'un Opérand */ + if(strlen(current_line->operand_txt) == 0) + { + printf(" => [Error] Empty DUM line : '%s %s %s' in file '%s' (line %d).\n",current_line->label_txt,current_line->opcode_txt,current_line->operand_txt,current_line->file->file_name,current_line->file_line_number); + return(1); + } + + /* On va rechercher le DEND et on marque toutes les lignes entre */ + for(dend_line=current_line; dend_line; dend_line=dend_line->next) + { + /* On ignore les lignes non valides */ + if(dend_line->is_valid == 0) + continue; + + /* On marque la ligne */ + dend_line->is_dum = 1; + if(dend_line != current_line) + dend_line->dum_line = current_line; + + if(dend_line->type == LINE_DIRECTIVE && !my_stricmp(dend_line->opcode_txt,"DEND")) + break; + + /* On ne devrait pas retomber sur un DUM */ + if(current_line != dend_line && dend_line->type == LINE_DIRECTIVE && !my_stricmp(dend_line->opcode_txt,"DUM")) + { + printf(" => [Error] DUM line with DUM found before DEND : '%s %s %s' in file '%s' (line %d).\n",current_line->label_txt,current_line->opcode_txt,current_line->operand_txt,current_line->file->file_name,current_line->file_line_number); + return(1); + } + } + + /* Pas de DEND ? */ + if(dend_line == NULL) + { + printf(" => [Error] DUM line without DEND : '%s %s %s' in file '%s' (line %d).\n",current_line->label_txt,current_line->opcode_txt,current_line->operand_txt,current_line->file->file_name,current_line->file_line_number); + return(1); + } + + /* On continue après */ + current_line = dend_line; + } + } + + /* OK */ + return(0); +} + + +/*******************************************************/ +/* CheckForErrLine() : Evalue toutes les lignes ERR. */ +/*******************************************************/ +int CheckForErrLine(struct omf_segment *current_omfsegment) +{ + int64_t value; + int is_reloc; + BYTE byte_count, bit_shift; + WORD offset_reference; + DWORD address_long; + char buffer_error[1024] = ""; + struct external *current_external; + struct source_file *first_file; + struct source_line *current_line; + + /* Récupère le fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /** Passe toutes les lignes ERR en revue **/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes non valides */ + if(current_line->is_valid == 0) + continue; + + /** On va rechercher les lignes ERR **/ + if(current_line->type == LINE_CODE && !my_stricmp(current_line->opcode_txt,"ERR")) + { + /* On repasse la ligne en Directive pour le fichier Output */ + current_line->type = LINE_DIRECTIVE; + + /* On vérifie la présence d'un Opérand, sinon on considère qu'il n'y a pas d'erreur */ + if(strlen(current_line->operand_txt) == 0) + continue; + + /** On va évaluer l'Opérande **/ + value = EvalExpressionAsInteger(current_line->operand_txt,&buffer_error[0],current_line,4,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) > 0) + { + /* Erreur dans l'évaluation */ + printf(" => [Error] Impossible to evaluate ERR expression '%s' (line %d, file '%s') : %s\n",current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + return(1); + } + + /** Si c'est différent de Zéro, c'est une erreur **/ + if((int) value != 0) + { + /* On force une erreur */ + printf(" => [Error] The evaluation of ERR expression '%s' is '0x%X' (line %d, file '%s')\n",current_line->operand_txt,(int)value,current_line->file_line_number,current_line->file->file_name); + return(1); + } + } + } + + /* OK */ + return(0); +} + + +/***********************************************************************/ +/* CheckForDirectPageLine() : Vérifie toutes les lignes Page Direct. */ +/***********************************************************************/ +int CheckForDirectPageLine(struct omf_segment *current_omfsegment) +{ + struct source_file *first_file; + struct source_line *current_line; + + /* Récupère le fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /** Passe toutes les lignes Page Direct en revue **/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes non valides */ + if(current_line->is_valid == 0) + continue; + + /** On va rechercher les lignes de code Page Direct **/ + if(current_line->type == LINE_CODE && IsPageDirectAddressMode(current_line->address_mode)) + { + /* On vérifie la présence d'un Opérande valide */ + if(current_line->operand_value == 0xFFFFFFFF) + continue; + + /** Si l'opérande n'est pas une addresse Page Direct => Error **/ + if((current_line->operand_value & 0xFFFFFF00) != 0x00000000) + { + /* On force une erreur */ + printf(" => [Bad Address Mode] Operand address '%s' (=0x%X) is located outside of the Direct Page (line %d, file '%s')\n",current_line->operand_txt,current_line->operand_value,current_line->file_line_number,current_line->file->file_name); + return(1); + } + } + } + + /* OK */ + return(0); +} + + +/**************************************************************************************************/ +/* ProcessDirectiveWithLabelLine() : Conversion des Lignes Directive avec Label en Ligne vides. */ +/**************************************************************************************************/ +int ProcessDirectiveWithLabelLine(struct omf_segment *current_omfsegment) +{ + int found; + struct source_file *first_file; + struct source_line *current_line; + struct source_line *other_line; + + /* Récupère le fichier Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /** Passe toutes les lignes Page Direct en revue **/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes non valides */ + if(current_line->is_valid == 0) + continue; + + /** On va rechercher les lignes DIRECTIVE **/ + if(current_line->type == LINE_DIRECTIVE && current_line->is_inside_macro == 0 && strlen(current_line->label_txt) > 0) + { + /* On vérifie que le label est utilisé = pointé par une autre ligne */ + for(other_line=first_file->first_line,found=0; other_line; other_line=other_line->next) + { + /* On ignore les lignes non valides */ + if(other_line->is_valid == 0) + continue; + + /* Cette ligne pointe vers la ligne DIRECTIVE */ + if(other_line->operand_address_long == current_line->address) + { + found = 1; + break; + } + } + + /** On passe la ligne en ligne EMPTY pour qu'elle soit affichée dans l'output **/ + if(found == 1) + current_line->type = LINE_EMPTY; + } + } + + /* OK */ + return(0); +} + +/*********************************************************/ +/* BuildSourceLine() : Décodage d'une ligne de Source. */ +/*********************************************************/ +struct source_line *BuildSourceLine(struct source_file *current_file, int line_number) +{ + struct source_line *current_line; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Allocation mémoire */ + current_line = (struct source_line *) calloc(1,sizeof(struct source_line)); + if(current_line == NULL) + return(NULL); + current_line->type = LINE_UNKNOWN; + + /* Remplissage */ + current_line->file_line_number = line_number+1; + current_line->line_data = current_file->tab_line[line_number]; + current_line->file = current_file; + + /* Cette ligne était dans le fichier Source (contrairement aux lignes venant des Macro ou des Lup) */ + current_line->is_in_source = 1; + + /* Par défaut, toute ligne est valide */ + current_line->is_valid = 1; + + /* Valeurs de E, C, M et X */ + strcpy(current_line->m,"?"); + strcpy(current_line->x,"?"); + + /* Reloc */ + strcpy(current_line->reloc," "); + + /* Adresse */ + current_line->address = -1; /* Pas encore déterminée */ + + /* Taille du code objet */ + current_line->nb_byte = -1; /* Pas encore déterminé */ + + /* La ligne interdit t'elle le Page Direct ? */ + current_line->no_direct_page = 0; + + /* Valeur de l'Opérande */ + current_line->operand_value = 0xFFFFFFFF; + + /* Adresse Longue du Label pointé par l'opérande */ + current_line->operand_address_long = 0xFFFFFFFF; + + /** Lignes commentaire **/ + strcpy(param->buffer_line,current_line->line_data); + CleanBuffer(param->buffer_line); + if(strlen(param->buffer_line) == 0 || param->buffer_line[0] == ';' || param->buffer_line[0] == '*') + { + /* On met du vide dans les champs */ + current_line->label_txt = strdup(""); + current_line->opcode_txt = strdup(""); + current_line->operand_txt = strdup(""); + current_line->comment_txt = strdup(""); + if(current_line->label_txt == NULL || current_line->opcode_txt == NULL || + current_line->operand_txt == NULL || current_line->comment_txt == NULL) + { + mem_free_sourceline(current_line); + return(NULL); + } + current_line->type = (strlen(param->buffer_line) == 0) ? LINE_EMPTY : LINE_COMMENT; + return(current_line); + } + + /*** Découpage de la ligne en 4 bloc : Label / Opcode / Operand / Commentaire ***/ + DecodeLine(current_line->line_data,param->buffer_label,param->buffer_opcode,param->buffer_operand,param->buffer_comment); + current_line->label_txt = strdup(param->buffer_label); + current_line->opcode_txt = strdup(param->buffer_opcode); + current_line->operand_txt = strdup(param->buffer_operand); + current_line->comment_txt = strdup(param->buffer_comment); + if(current_line->label_txt == NULL || current_line->opcode_txt == NULL || + current_line->operand_txt == NULL || current_line->comment_txt == NULL) + { + mem_free_sourceline(current_line); + return(NULL); + } + + /* Renvoi la ligne */ + return(current_line); +} + + +/*********************************************************/ +/* DuplicateSourceLine() : Duplique une ligne de Code. */ +/*********************************************************/ +struct source_line *DuplicateSourceLine(struct source_line *current_line) +{ + struct source_line *new_line; + + /* Allocation mémoire */ + new_line = (struct source_line *) calloc(1,sizeof(struct source_line)); + if(new_line == NULL) + return(NULL); + + /* Recopie les valeurs */ + new_line->line_number = current_line->line_number; + new_line->file_line_number = current_line->file_line_number; + new_line->file = current_line->file; + new_line->type = current_line->type; + new_line->type_aux = current_line->type_aux; + new_line->is_in_source = current_line->is_in_source; + new_line->is_valid = current_line->is_valid; + new_line->no_direct_page = current_line->no_direct_page; + new_line->use_direct_page = current_line->use_direct_page; + new_line->is_inside_macro = current_line->is_inside_macro; + new_line->is_dum = current_line->is_dum; + new_line->dum_line = current_line->dum_line; + new_line->cond_level = current_line->cond_level; + strcpy(new_line->m,current_line->m); + strcpy(new_line->x,current_line->x); + new_line->variable = current_line->variable; + new_line->macro = current_line->macro; + new_line->bank = current_line->bank; + new_line->address = current_line->address; + new_line->operand_value = current_line->operand_value; + new_line->operand_address_long = current_line->operand_address_long; + new_line->nb_byte = current_line->nb_byte; + new_line->opcode_byte = current_line->opcode_byte; + new_line->address_mode = current_line->address_mode; + new_line->address_is_rel = current_line->address_is_rel; + memcpy(new_line->operand_byte,current_line->operand_byte,4); + strcpy(new_line->reloc,current_line->reloc); + new_line->next = NULL; + + /* Duplique certaines valeurs */ + if(current_line->line_data != NULL) + { + new_line->line_data = strdup(current_line->line_data); + if(new_line->line_data == NULL) + { + mem_free_sourceline(new_line); + return(NULL); + } + } + if(current_line->data != NULL) + { + new_line->data = current_line->data = (unsigned char *) calloc(new_line->nb_byte+1,sizeof(unsigned char)); + if(new_line->data == NULL) + { + mem_free_sourceline(new_line); + return(NULL); + } + memcpy(new_line->data,current_line->data,new_line->nb_byte+1); + } + new_line->label_txt = strdup(current_line->label_txt); + new_line->opcode_txt = strdup(current_line->opcode_txt); + new_line->operand_txt = strdup(current_line->operand_txt); + new_line->comment_txt = strdup(current_line->comment_txt); + if(new_line->label_txt == NULL || new_line->opcode_txt == NULL || new_line->operand_txt == NULL || new_line->comment_txt == NULL) + { + mem_free_sourceline(new_line); + return(NULL); + } + + /* Renvoie la ligne */ + return(new_line); +} + + +/************************************************************************/ +/* BuildEmptyLabelLine() : Crée une ligne de Code vide avec un Label. */ +/************************************************************************/ +struct source_line *BuildEmptyLabelLine(char *label, struct source_line *current_line) +{ + struct source_line *new_line; + + /* Allocation mémoire */ + new_line = (struct source_line *) calloc(1,sizeof(struct source_line)); + if(new_line == NULL) + return(NULL); + + /* Recopie les valeurs */ + new_line->line_number = current_line->line_number; + new_line->file_line_number = current_line->file_line_number; + new_line->file = current_line->file; + new_line->type = LINE_EMPTY; + new_line->type_aux = current_line->type_aux; + new_line->is_in_source = current_line->is_in_source; + new_line->is_valid = current_line->is_valid; + new_line->no_direct_page = current_line->no_direct_page; + new_line->use_direct_page = current_line->use_direct_page; + new_line->is_inside_macro = current_line->is_inside_macro; + new_line->is_dum = current_line->is_dum; + new_line->dum_line = current_line->dum_line; + new_line->cond_level = current_line->cond_level; + strcpy(new_line->m,current_line->m); + strcpy(new_line->x,current_line->x); + new_line->variable = NULL; + new_line->macro = NULL; + new_line->bank = current_line->bank; + new_line->address = current_line->address; + new_line->operand_value = current_line->operand_value; + new_line->operand_address_long = current_line->operand_address_long; + new_line->nb_byte = 0; + new_line->opcode_byte = 0x00; + new_line->address_mode = current_line->address_mode; + new_line->address_is_rel = current_line->address_is_rel; + memset(new_line->operand_byte,0,4); + strcpy(new_line->reloc,current_line->reloc); + new_line->next = NULL; + + /* Duplique certaines valeurs */ + new_line->line_data = strdup(""); + if(new_line->line_data == NULL) + { + mem_free_sourceline(new_line); + return(NULL); + } + new_line->label_txt = strdup(label); + new_line->opcode_txt = strdup(""); + new_line->operand_txt = strdup(""); + new_line->comment_txt = strdup(""); + if(new_line->label_txt == NULL || new_line->opcode_txt == NULL || new_line->operand_txt == NULL || new_line->comment_txt == NULL) + { + mem_free_sourceline(new_line); + return(NULL); + } + + /* Renvoie la ligne */ + return(new_line); +} + + +/*****************************************************************/ +/* DecodeLine() : Décode une ligne en séparant les 4 éléments. */ +/*****************************************************************/ +void DecodeLine(char *line_data, char *label_rtn, char *opcode_rtn, char *operand_rtn, char *comment_rtn) +{ + int has_data, nb_separator; + struct item *all_item; + struct item *current_item; + struct item *opcode_item = NULL; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + strcpy(label_rtn,""); + strcpy(opcode_rtn,""); + strcpy(operand_rtn,""); + strcpy(comment_rtn,""); + + /** Découpe la ligne en éléments séparés par des espaces ou des tab (en tenant compte des commentaires et des chaines '' ou "") **/ + all_item = ExtractAllIem(line_data); + if(all_item == NULL) + return; /* Ligne vide */ + + /** Cas particulier : Que des sépérateurs **/ + for(has_data=0, current_item = all_item; current_item; current_item = current_item->next) + if(current_item->type == TYPE_DATA) + { + has_data = 1; + break; + } + if(has_data == 0) + { + mem_free_item_list(all_item); + return; /* Ligne vide */ + } + + /** Cas particulier : Ligne de commentaire **/ + for(current_item = all_item; current_item; current_item = current_item->next) + if(current_item->type == TYPE_DATA) + { + if(current_item->name[0] == '*' || current_item->name[0] == ';') + { + strcpy(comment_rtn,current_item->name); + mem_free_item_list(all_item); + return; + } + break; + } + + /** Commentaire : Valeur qui commence par un ; **/ + for(current_item = all_item; current_item->next; current_item = current_item->next) + if(current_item->next->type == TYPE_DATA && current_item->next->name[0] == ';') + { + /* Garde le commentaire, libère la suite */ + strcpy(comment_rtn,current_item->next->name); + mem_free_item_list(current_item->next); + current_item->next = NULL; + break; + } + + /** Label : Tout ce qui est collé à gauche **/ + if(all_item->type == TYPE_DATA) + strcpy(label_rtn,all_item->name); + + /** Opcode : DATA qui est après le 1er séparateur **/ + for(nb_separator=0,current_item = all_item; current_item; current_item = current_item->next) + { + if(current_item->type == TYPE_SEPARATOR) + nb_separator++; + else if(current_item->type == TYPE_DATA && nb_separator == 1) + { + strcpy(opcode_rtn,current_item->name); + opcode_item = current_item; + break; + } + } + + /** Operand : Ce qu'il reste (la partie commentaire a déjà été supprimée) **/ + if(opcode_item != NULL) + { + for(current_item = opcode_item->next; current_item; current_item = current_item->next) + { + if(current_item->type == TYPE_SEPARATOR) + { + if(strlen(operand_rtn) > 0) + if(operand_rtn[strlen(operand_rtn)-1] != ' ') + strcat(operand_rtn," "); + } + else + strcat(operand_rtn,current_item->name); + } + } + + /* Libération mémoire */ + mem_free_item_list(all_item); + + /** On supprime les espaces et les \t entourant les valeurs **/ + CleanBuffer(label_rtn); + CleanBuffer(opcode_rtn); + CleanBuffer(operand_rtn); + CleanBuffer(comment_rtn); +} + + +/*******************************************************************/ +/* AddDateLine() : Ajout d'une ligne Date pour la directive DAT. */ +/*******************************************************************/ +static void AddDateLine(struct source_line *current_line, struct omf_segment *current_omfsegment) +{ + struct source_line *new_line; + char buffer[256]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* On va décoder le type de Date demandé */ + if(!my_stricmp(current_line->operand_txt,"1")) + sprintf(buffer,"\"%s\"",param->date_1); + else if(!my_stricmp(current_line->operand_txt,"2")) + sprintf(buffer,"\"%s\"",param->date_2); + else if(!my_stricmp(current_line->operand_txt,"3")) + sprintf(buffer,"\"%s\"",param->date_3); + else if(!my_stricmp(current_line->operand_txt,"4")) + sprintf(buffer,"\"%s\"",param->date_4); + else if(!my_stricmp(current_line->operand_txt,"5")) + sprintf(buffer,"'%s'",param->date_1); + else if(!my_stricmp(current_line->operand_txt,"6")) + sprintf(buffer,"'%s'",param->date_2); + else if(!my_stricmp(current_line->operand_txt,"7")) + sprintf(buffer,"'%s'",param->date_3); + else if(!my_stricmp(current_line->operand_txt,"8")) + sprintf(buffer,"'%s'",param->date_4); + else + return; + + /** Création d'une Ligne DATA **/ + new_line = BuildEmptyLabelLine("",current_line); + if(new_line == NULL) + { + printf(" => [Error] Impossible to allocate memory to insert DAT value (line %d, file '%s')\n",current_line->file_line_number,current_line->file->file_path); + return; + } + free(new_line->opcode_txt); + new_line->opcode_txt = NULL; + free(new_line->operand_txt); + new_line->operand_txt = NULL; + + /* Nouvelles valeurs */ + new_line->type = LINE_DATA; + new_line->opcode_txt = strdup("ASC"); + new_line->operand_txt = strdup(buffer); + if(new_line->opcode_txt == NULL || new_line->operand_txt == NULL) + { + mem_free_sourceline(new_line); + printf(" => [Error] Impossible to allocate memory to insert DAT value (line %d, file '%s')\n",current_line->file_line_number,current_line->file->file_path); + return; + } + + /* Insère la ligne après la ligne DAT */ + new_line->next = current_line->next; + current_line->next = new_line; +} + + +/*****************************************************************************/ +/* mem_free_sourceline() : Libération mémoire de la structure source_line. */ +/*****************************************************************************/ +void mem_free_sourceline(struct source_line *current_sourceline) +{ + if(current_sourceline) + { + if(current_sourceline->label_txt) + free(current_sourceline->label_txt); + + if(current_sourceline->opcode_txt) + free(current_sourceline->opcode_txt); + + if(current_sourceline->operand_txt) + free(current_sourceline->operand_txt); + + if(current_sourceline->comment_txt) + free(current_sourceline->comment_txt); + + if(current_sourceline->data) + free(current_sourceline->data); + + free(current_sourceline); + } +} + + +/*******************************************************************/ +/* mem_free_sourceline_list() : Libère la liste de ligne source. */ +/*******************************************************************/ +void mem_free_sourceline_list(struct source_line *first_sourceline) +{ + struct source_line *current_sourceline; + struct source_line *next_sourceline; + + /** Libère la liste chainée de structure **/ + for(current_sourceline = first_sourceline; current_sourceline; ) + { + next_sourceline = current_sourceline->next; + mem_free_sourceline(current_sourceline); + current_sourceline = next_sourceline; + } +} + + +/******************************************************************/ +/* mem_free_label() : Libération mémoire de la structure label. */ +/******************************************************************/ +void mem_free_label(struct label *current_label) +{ + if(current_label) + { + if(current_label->name) + free(current_label->name); + + free(current_label); + } +} + + +/************************************************************************/ +/* mem_free_variable() : Libération mémoire de la structure variable. */ +/************************************************************************/ +void mem_free_variable(struct variable *current_variable) +{ + if(current_variable) + { + if(current_variable->name) + free(current_variable->name); + + free(current_variable); + } +} + + +/******************************************************************************/ +/* mem_free_equivalence() : Libération mémoire de la structure equivalence. */ +/******************************************************************************/ +void mem_free_equivalence(struct equivalence *current_equivalence) +{ + if(current_equivalence) + { + if(current_equivalence->name) + free(current_equivalence->name); + + if(current_equivalence->value) + free(current_equivalence->value); + + free(current_equivalence); + } +} + + +/************************************************************************/ +/* mem_free_external() : Libération mémoire de la structure external. */ +/************************************************************************/ +void mem_free_external(struct external *current_external) +{ + if(current_external) + { + if(current_external->name) + free(current_external->name); + + free(current_external); + } +} + + +/********************************************************************/ +/* mem_free_global() : Libération mémoire de la structure global. */ +/********************************************************************/ +void mem_free_global(struct global *current_global) +{ + if(current_global) + { + if(current_global->name) + free(current_global->name); + + free(current_global); + } +} + +/***********************************************************************/ diff --git a/Source/a65816_Line.h b/Source/a65816_Line.h new file mode 100644 index 0000000..48f0f79 --- /dev/null +++ b/Source/a65816_Line.h @@ -0,0 +1,219 @@ +/***********************************************************************/ +/* */ +/* a65816_Line.h : Header pour la gestion des lignes. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +#define LINE_UNKNOWN 0 /* Ligne dont on ne connait pas encore le type / qu'on a rrive pas à décoder */ +#define LINE_COMMENT 1 /* Ligne ne contenant qu'un commentaire */ +#define LINE_DIRECTIVE 2 /* Directive d'assemblage (PUT, USE, IF, XC...) */ +#define LINE_EQUIVALENCE 3 /* Ligne définissant une constante (EQU, =) */ +#define LINE_VARIABLE 4 /* Ligne définissant une variable (pour les boucles...) */ +#define LINE_CODE 5 /* Ligne de code avec au moins un Opcode */ +#define LINE_DATA 6 /* Ligne stockant des variables (HEX, DA, ASC, STR...)*/ +#define LINE_MACRO 7 /* Ligne appelant une macro */ +#define LINE_EMPTY 8 /* Ligne avec seulement un Label */ +#define LINE_GLOBAL 9 /* Label Global définissant un point d'entrée pour les InterSeg */ +#define LINE_EXTERNAL 10 /* Label Externe définissant une adresse d'un autre segment */ + +#define LINE_MACRO_DEF 1 + +#define AM_UNKOWN 0 /* Not recognize */ +#define AM_IMPLICIT 1 /* A Implicit */ +#define AM_ABSOLUTE 2 /* addr2 Absolute */ +#define AM_ABSOLUTE_INDEXED_X_INDIRECT 3 /* (addr2,X) Absolute Indexed,X Indirect */ +#define AM_ABSOLUTE_INDEXED_X 4 /* addr2,X Absolute Indexed,X */ +#define AM_ABSOLUTE_INDEXED_Y 5 /* addr2,Y Absolute Indexed,Y */ +#define AM_ABSOLUTE_INDIRECT 6 /* (addr2) Absolute Indirect */ +#define AM_ABSOLUTE_INDIRECT_LONG 7 /* [addr2] Absolute Indirect Long */ +#define AM_ABSOLUTE_LONG 8 /* addr3 Absolute Long */ +#define AM_ABSOLUTE_LONG_INDEXED_X 9 /* addr3,X Absolute Long Indexed,X */ +#define AM_DIRECT_PAGE 10 /* dp Direct Page */ +#define AM_DIRECT_PAGE_INDEXED_X 11 /* dp,X Direct Page Indexed,X */ +#define AM_DIRECT_PAGE_INDEXED_Y 12 /* dp,Y Direct Page Indexed,Y */ +#define AM_DIRECT_PAGE_INDIRECT 13 /* (dp) Direct Page Indirect */ +#define AM_DIRECT_PAGE_INDIRECT_LONG 14 /* [dp] Direct Page Indirect Long */ +#define AM_DIRECT_PAGE_INDEXED_X_INDIRECT 15 /* (dp,X) Direct Page Indexed,X Indirect */ +#define AM_DIRECT_PAGE_INDIRECT_INDEXED_Y 16 /* (dp),Y Direct Page Indirect Indexed,Y */ +#define AM_DIRECT_PAGE_INDIRECT_LONG_INDEXED_Y 17 /* [dp],Y Direct Page Indirect Long Indexed,Y */ +#define AM_IMMEDIATE_8 18 /* #const 8 Immediate 8 bit */ +#define AM_IMMEDIATE_16 19 /* #const 16 Immediate 16 bit */ +#define AM_PC_RELATIVE 20 /* relative1 Program Counter Relative 8 bit (BRA, BEQ, BPL...) */ +#define AM_PC_RELATIVE_LONG 21 /* relative2 Program Counter Relative Long (BRL et PER) */ +#define AM_STACK_RELATIVE_INDIRECT_INDEXED_Y 22 /* (sr,S),Y Stack Relative Indirect Indexed,Y */ +#define AM_STACK_PC_RELATIVE_LONG 23 /* label Stack PC Relative Long */ +#define AM_STACK_RELATIVE 24 /* sr,S Stack Relative */ +#define AM_BLOCK_MOVE 25 /* Src,Dst Block Move (MVN, MVP) */ + +#define FORMAT_DECIMAL 1 +#define FORMAT_HEXA 2 +#define FORMAT_BINARY 3 +#define FORMAT_ASCII 4 +#define FORMAT_LABEL 5 +#define FORMAT_VARIABLE 6 +#define FORMAT_EXTERNAL 7 /* Label Externe au module = Adresse Longue */ + +struct source_line +{ + char *line_data; /* Ligne telle qu'elle était dans le fichier Source */ + int line_number; /* Numéro de la ligne global */ + + int file_line_number; /* Numéro de la ligne dans le fichier */ + struct source_file *file; + + int type; /* Type de ligne : LINE_COMMENT, LINE_DIRECTIVE, LINE_CODE, LINE_MACRO */ + int type_aux; /* Type Auxiliaire : LINE_MACRO_DEF */ + int is_in_source; /* Cette ligne est dans le code source d'origine (et non pas dans une Macro qui a été développée) */ + int is_valid; /* Cette ligne sera conservé dans le code final */ + int no_direct_page; /* On ne doit pas générer de code Page Direct : LDA\ $0000 */ + int use_direct_page; /* On doit générer de code Page Direct : LDA $00 */ + + int was_local_label; /* Ce label :local a été remplacé par un nom unique */ + + int is_inside_macro; /* Cette ligne de code fait partie d'une déclaration d'une Macro présente dans le fichier Source */ + + int is_dum; /* Cette ligne est stockée entre 2 DUM - DEND */ + struct source_line *dum_line; /* Ligne déclarant le DUM */ + + char *label_txt; /* Découpage de la ligne en 4 parties : Label Opcode Operand ; Comment */ + char *opcode_txt; + char *operand_txt; + char *comment_txt; + + int cond_level; /* Niveau de la conditiion 0->N IF [ELSE] FIN | DO [ELSE] FIN */ + int do_level; /* Niveau de la condition IF ELSE FIN pour l'évaluation préliminaire */ + + char m[2]; /* M : 0/1/? = Acc size (0=16bit, 1=8bit) */ + char x[2]; /* X : 0/1/? = X,Y size (0=16bit, 1=8bit) */ + + struct variable *variable; /* Si cette ligne est une variable, on pointe sur sa valeur */ + + struct macro *macro; /* Si cette ligne est un appel à une Macro, on pointe vers elle */ + + int bank; /* Bank mémoire de la ligne */ + int address; /* Adresse de la ligne */ + int is_fix_address; /* Cette ligne a une adresse fixe (cas des lignes situées dans [ORG $Addr ORG] pour un OMF ou un Single Binary */ + int global_bank; + int global_address; /* Adresse de la ligne si le ORG $Addr n'était pas là (utile pour reloger les adresses situées entre un [ORG $Addr ORG] */ + + int nb_byte; /* Taille de la ligne : 1 + Operand Size */ + unsigned char opcode_byte; /* Opcode */ + int address_mode; /* Mode d'addressage AM_ */ + int address_is_rel; /* L'adresse pointée par l'opcode est une adresse d'une zone relative : si < 0x100, cela ne la fera pas basculer dans du Page Direct */ + unsigned char operand_byte[4]; /* Operande */ + unsigned char *data; /* Data */ + + DWORD operand_value; /* Résultat de l'évaluation de l'Opérande, avant la troncature due au nb de byte de l'operande */ + DWORD operand_address_long; /* Si l'opérande pointe vers une adresse, on garde ici la version longue de l'adresse : Bank/HighLow */ + struct relocate_address *external_address; /* En cas d'utilisation d'une adresse Externe, on conserve un pointeur */ + + char reloc[16]; /* Information de Relocate : Nb Byte >> Bit Shift */ + + struct source_line *next; +}; + +struct label +{ + char *name; + struct source_line *line; /* Le is_dum de la ligne permet de savoir si ce label provient d'une section DUM (= Adresse Fixe = Non relogeable) */ + + int is_global; /* Ce label est un point d'entrée dans le Segment */ + + struct label *next; +}; + +struct external +{ + /* Référence interne */ + char *name; + struct source_line *source_line; + + /* Référence externe */ + struct omf_segment *external_segment; + struct label *external_label; + + struct external *next; +}; + +struct global +{ + char *name; + struct source_line *source_line; /* Ligne source contenant le ENT Label1,Label2... */ + + struct global *next; +}; + +struct equivalence +{ + char *name; + char *value; + + struct source_line *source_line; /* Si l'équivalence provient du source, on pointe la ligne (elle peut aussi venir des fichiers Macro) */ + + struct equivalence *next; +}; + +struct variable +{ + char *name; + + int is_pound; /* # */ + int is_dollar; /* $ */ + int is_pound_dollar; /* #$ */ + + int64_t value; + + struct variable *next; +}; + +struct relocate_address +{ + BYTE ByteCnt; /* Number of Bytes to be relocated (1,2,3 ou 4) */ + BYTE BitShiftCnt; /* Opérations >> ou << */ + WORD OffsetPatch; /* Offset of the first Byte to be Patched */ + WORD OffsetReference; /* Adresse */ + + struct external *external; /* On fait appel à un Label Externe (NULL si interne) */ + unsigned char *object_line; /* Adresse de la zone à patcher dans la line (pour les label externes) */ + + int processed; /* Déjà traité */ + + struct relocate_address *next; +}; + +int DecodeLineType(struct source_line *,struct macro *,struct omf_segment *,struct omf_project *); +void BuildReferenceTable(struct omf_segment *); +int BuildLabelTable(struct omf_segment *); +int BuildEquivalenceTable(struct omf_segment *); +int BuildExternalTable(struct omf_segment *); +int BuildVariableTable(struct omf_segment *); +int ProcessAllLocalLabel(struct omf_segment *); +int ProcessAllVariableLabel(struct omf_segment *); +int ProcessAllAsteriskLine(struct omf_segment *); +int ProcessEquivalence(struct omf_segment *); +int ProcessLineEquivalence(struct source_line *,struct omf_segment *); +int CheckForDuplicatedLabel(struct omf_segment *); +int CheckForUnknownLine(struct omf_segment *); +int CheckForDumLine(struct omf_segment *); +int CheckForErrLine(struct omf_segment *); +int CheckForDirectPageLine(struct omf_segment *); +int ProcessDirectiveWithLabelLine(struct omf_segment *); +int ProcessMXDirective(struct omf_segment *); +int EvaluateVariableLine(struct source_line *,struct omf_segment *); +int ComputeLineAddress(struct omf_segment *,struct omf_project *); +struct relocate_address *BuildRelocateAddress(BYTE,BYTE,WORD,WORD,struct external *,struct omf_segment *); +struct source_line *BuildSourceLine(struct source_file *,int); +struct source_line *DuplicateSourceLine(struct source_line *); +struct source_line *BuildEmptyLabelLine(char *,struct source_line *); +void DecodeLine(char *,char *,char *,char *,char *); +void mem_free_sourceline(struct source_line *); +void mem_free_sourceline_list(struct source_line *); +void mem_free_label(struct label *); +void mem_free_equivalence(struct equivalence *); +void mem_free_variable(struct variable *); +void mem_free_external(struct external *); +void mem_free_global(struct global *); + +/***********************************************************************/ diff --git a/Source/a65816_Link.c b/Source/a65816_Link.c new file mode 100644 index 0000000..4d751ad --- /dev/null +++ b/Source/a65816_Link.c @@ -0,0 +1,1165 @@ +/***********************************************************************/ +/* */ +/* a65816_Link.c : Module d'Assemblage / Linkage d'un source 65c816. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +#include +#include +#include +#include +#include + +/** Platform dependent code **/ +#if defined(WIN32) || defined(WIN64) +/* Windows */ +#else +/* Linux + MacOS */ +#include /* unlink() */ +#endif + +#include "Dc_Library.h" +#include "a65816_Line.h" +#include "a65816_File.h" +#include "a65816_Lup.h" +#include "a65816_Macro.h" +#include "a65816_Cond.h" +#include "a65816_Code.h" +#include "a65816_Data.h" +#include "a65816_OMF.h" +#include "a65816_Link.h" + +static int Assemble65c816Segment(struct omf_project *,struct omf_segment *,char *); +static int Link65c816Segment(struct omf_project *, struct omf_segment *); +static int IsLinkFile(struct source_file *); +static struct omf_project *BuildSingleSegment(char *); +static struct omf_project *BuildLinkFile(struct source_file *); + +/**************************************************************************/ +/* AssembleLink65c816() : Assemble et Links des fichiers source 65c816. */ +/**************************************************************************/ +int AssembleLink65c816(char *master_file_path, char *macro_folder_path, int verbose_mode) +{ + DWORD org_offset; + int i, error, is_link_file; + char file_name[1024] = ""; + char file_error_path[1024]; + struct source_file *master_file; + struct omf_project *current_omfproject; + struct omf_segment *current_omfsegment; + struct omf_segment *tmp_omfsegment; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Nom du fichier */ + strcpy(file_name,master_file_path); + for(i=(int)strlen(master_file_path); i>=0; i--) + if(master_file_path[i] == '\\' || master_file_path[i] == '/') + { + strcpy(file_name,&master_file_path[i+1]); + break; + } + + /* Fichier Error_Output.txt */ + sprintf(file_error_path,"%serror_output.txt",param->current_folder_path); + unlink(file_error_path); + + /* Allocation d'un OMF Segment temporaire */ + tmp_omfsegment = mem_alloc_omfsegment(); + if(tmp_omfsegment == NULL) + { + strcpy(param->buffer_error,"Impossible to allocate memory to build temporary segment structure"); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + my_Memory(MEMORY_SET_OMFSEGMENT,tmp_omfsegment,NULL,NULL); + + /** Charge en mémoire le fichier principal **/ + master_file = LoadOneSourceFile(master_file_path,file_name,0); + if(master_file == NULL) + { + sprintf(param->buffer_error,"Impossible to load Master Source file '%s'",master_file_path); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /** Est-ce un fichier Link ou un ficher Source **/ + is_link_file = IsLinkFile(master_file); + if(is_link_file == 0) + { + /* Libération mémoire du fichier Link */ + mem_free_sourcefile(master_file,1); + mem_free_omfsegment(tmp_omfsegment); + my_Memory(MEMORY_SET_OMFSEGMENT,NULL,NULL,NULL); + + /* Init File */ + my_File(FILE_INIT,NULL); + + /** Création d'1 omf_header + 1 omf_segment **/ + current_omfproject = BuildSingleSegment(master_file_path); + if(current_omfproject == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to process Master Source file '%s'",master_file_path); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Déclare le Segment OMF courrant */ + my_Memory(MEMORY_SET_OMFSEGMENT,current_omfproject->first_segment,NULL,NULL); + + /*** Mono Segment : Assemble les fichiers Source + Création du fichier Output.txt pour 1 Segment ***/ + printf(" + Assemble project files...\n"); + error = Assemble65c816Segment(current_omfproject,current_omfproject->first_segment,macro_folder_path); + if(error) + { + /* Création du fichier Output */ + CreateOutputFile(file_error_path,current_omfproject->first_segment,current_omfproject); + + /* Libération mémoire */ + mem_free_omfproject(current_omfproject); + my_Memory(MEMORY_SET_OMFSEGMENT,NULL,NULL,NULL); + my_File(FILE_FREE,NULL); + + /* Code Erreur */ + return(error); + } + + /*** Mono Segment : Link les fichiers Source pour 1 Segment ***/ + printf(" + Link project files...\n"); + error = Link65c816Segment(current_omfproject,current_omfproject->first_segment); + if(error) + { + /* Libération mémoire : OMF Project + OMF Segment */ + mem_free_omfproject(current_omfproject); + my_Memory(MEMORY_SET_OMFSEGMENT,NULL,NULL,NULL); + my_File(FILE_FREE,NULL); + + /* Code Erreur */ + return(error); + } + + /** Create OMF File / Binary File **/ + if(current_omfproject->first_segment->is_omf == 1) + { + /* OMF Mono Segment */ + printf(" o Build OMF output file...\n"); + BuildOMFFile(param->current_folder_path,current_omfproject); + } + else + { + /* Binaire à adresse fixe */ + printf(" o Build Binary output file...\n"); + BuildObjectFile(param->current_folder_path,current_omfproject->first_segment,current_omfproject); + } + + /** Dump Code as Output Text File **/ + if(verbose_mode) + { + /* Nom du fichier _Output.txt */ + sprintf(param->output_file_path,"%s%s_Output.txt",param->current_folder_path,current_omfproject->first_segment->object_name); /* Mono Segment */ + + /* Création du fichier Output */ + printf(" + Create Output Text file...\n"); + CreateOutputFile(param->output_file_path,current_omfproject->first_segment,current_omfproject); + } + + /* Libération mémoire */ + mem_free_omfproject(current_omfproject); + my_Memory(MEMORY_SET_OMFSEGMENT,NULL,NULL,NULL); + my_File(FILE_FREE,NULL); + } + else + { + /** Multi Segments : Assemble + Link tous les Segments **/ + printf(" + Loading Link file...\n"); + + /** Chargement du fichier Link : 1 omh_hearder + N omf_segment **/ + current_omfproject = BuildLinkFile(master_file); + if(current_omfproject == NULL) + { + mem_free_sourcefile(master_file,1); + sprintf(param->buffer_error,"Impossible to load Link file '%s'",master_file_path); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Libération mémoire */ + mem_free_sourcefile(master_file,1); + + /*********************************************************/ + /*** On va enchainer l'assemblage de tous les Segments ***/ + /*********************************************************/ + for(i=0,org_offset = 0,current_omfsegment=current_omfproject->first_segment; current_omfsegment; current_omfsegment=current_omfsegment->next,i++) + { + /* Init File */ + my_File(FILE_INIT,NULL); + + /* Déclare le Segment OMF courrant */ + my_Memory(MEMORY_SET_OMFSEGMENT,current_omfsegment,NULL,NULL); + + /* Donne un numéro au Segment (décale en cas d'ExpressLoad) */ + current_omfsegment->segment_number = i + 1 + ((current_omfproject->express_load == 1 && current_omfproject->nb_segment > 1) ? 1 : 0); + + /* Donne une adresse ORG pour les Fixed-Address Single-Binary */ + if(current_omfproject->is_single_binary == 1) + { + current_omfsegment->has_org_address = 1; + current_omfsegment->org_address = current_omfproject->org_address_tab[current_omfsegment->file_number-1] + org_offset; + } + + /*** Segment #n : Assemble les fichiers Source + Création du fichier Output.txt pour 1 Segment ***/ + printf(" + Assemble project files for Segment #%02X :\n",current_omfsegment->segment_number); + error = Assemble65c816Segment(current_omfproject,current_omfsegment,macro_folder_path); + if(error) + { + /* Création du fichier Output */ + CreateOutputFile(file_error_path,current_omfsegment,current_omfproject); + + /* Libération mémoire : OMF Project + OMF Segment */ + mem_free_omfproject(current_omfproject); + my_Memory(MEMORY_SET_OMFSEGMENT,NULL,NULL,NULL); + my_File(FILE_FREE,NULL); + + /* Code Erreur */ + return(error); + } + + /* Met à jour la ORG Address du Segment suivant (pour les Fixed-Address SingleBinary), puis remis à zero entre les fichiers */ + org_offset += current_omfsegment->object_length; + if(current_omfsegment->next != NULL) + if(current_omfsegment->file_number != current_omfsegment->next->file_number) + org_offset = 0; + } + + /***********************************************************************/ + /*** On va générer les Segments OMF (Header + Body) ou Fixed Address ***/ + /***********************************************************************/ + for(current_omfsegment=current_omfproject->first_segment; current_omfsegment; current_omfsegment=current_omfsegment->next) + { + /*** Segment #n : Link les fichiers Source pour 1 Segment ***/ + printf(" + Link project files for Segment #%02X...\n",current_omfsegment->segment_number); + error = Link65c816Segment(current_omfproject,current_omfsegment); + if(error) + { + /* Libération mémoire : OMF Project + OMF Segment */ + mem_free_omfproject(current_omfproject); + my_Memory(MEMORY_SET_OMFSEGMENT,NULL,NULL,NULL); + my_File(FILE_FREE,NULL); + + /* Code Erreur */ + return(error); + } + } + + /** Création du Segment ~ExpressLoad **/ + if(current_omfproject->is_multi_fixed != 1 && current_omfproject->express_load == 1 && current_omfproject->nb_segment > 1) + { + printf(" + Build ExpressLoad into Segment #01...\n"); + error = BuildExpressLoadSegment(current_omfproject); + if(error) + { + /* Libération mémoire : OMF Project + OMF Segment */ + mem_free_omfproject(current_omfproject); + my_Memory(MEMORY_SET_OMFSEGMENT,NULL,NULL,NULL); + my_File(FILE_FREE,NULL); + return(error); + } + } + + /***************************************************************************************/ + /** Create OMF File Multi-Segments / OMF File Mono-Segment / Binary Multi-Fixed files **/ + /***************************************************************************************/ + if(current_omfproject->is_multi_fixed == 1 && current_omfproject->is_single_binary == 0) + { + /** On va créer les fichiers Binaire de tous les Segments **/ + printf(" + Build Binary output files...\n"); + for(current_omfsegment=current_omfproject->first_segment; current_omfsegment; current_omfsegment=current_omfsegment->next) + { + /* Création du fichier Binaire à adresse fixe */ + BuildObjectFile(param->current_folder_path,current_omfsegment,current_omfproject); + } + } + else if(current_omfproject->is_multi_fixed == 1 && current_omfproject->is_single_binary == 1) + { + /** On va créer le fichier Binaire de tous les Segments concaténés **/ + printf(" + Build Binary output file%s...\n",(current_omfproject->nb_file==1)?"":"s"); + + /* Création du/des fichiers Binaire à adresse fixe groupés ensemble */ + for(i=0; inb_file; i++) + BuildSingleObjectFile(param->current_folder_path,i,current_omfproject); + } + else + { + /** Create OMF File Multi-Segments (ou Mono Segment mais disposant de son Link File) **/ + printf(" + Build OMF output file...\n"); + BuildOMFFile(param->current_folder_path,current_omfproject); + } + + /******************************/ + /** Dump as Output Text File **/ + /******************************/ + if(verbose_mode) + { + /* Création du/des fichiers Output Text */ + printf(" + Create Output Text file%s...\n",(current_omfproject->nb_segment == 1)?"":"s"); + + /** On va créer les fichiers Output.txt de tous les Segments (sauf l'ExpressLoad) **/ + for(current_omfsegment=current_omfproject->first_segment; current_omfsegment; current_omfsegment=current_omfsegment->next) + { + /* On ne Dump pas l'ExpressLoad */ + if(current_omfsegment->segment_number == 1 && !my_stricmp(current_omfsegment->segment_name,"~ExpressLoad")) + continue; + + /* Nom du fichier _Output.txt */ + if(current_omfproject->nb_segment == 1) /* Mono Segment */ + sprintf(param->output_file_path,"%s%s_Output.txt",param->current_folder_path,current_omfsegment->object_name); + else if(current_omfproject->nb_segment > 1 && current_omfproject->is_multi_fixed == 0) /* Multi Segment OMF */ + sprintf(param->output_file_path,"%s%s_S%02X_%s_Output.txt",param->current_folder_path,current_omfproject->dsk_name_tab[0],current_omfsegment->segment_number,current_omfsegment->object_name); + else if(current_omfproject->nb_segment > 1 && current_omfproject->is_multi_fixed == 1 && current_omfproject->is_single_binary == 0) /* Multi Segment Fixed */ + sprintf(param->output_file_path,"%s%s_S%02X_Output.txt",param->current_folder_path,(strlen(current_omfsegment->segment_name)==0)?current_omfsegment->object_name:current_omfsegment->segment_name,current_omfsegment->segment_number); + else if(current_omfproject->nb_segment > 1 && current_omfproject->is_multi_fixed == 1 && current_omfproject->is_single_binary == 1) /* Multi Segment Fixed Single Binary */ + sprintf(param->output_file_path,"%s%s_S%02X_%s_Output.txt",param->current_folder_path,current_omfproject->dsk_name_tab[current_omfsegment->file_number-1],current_omfsegment->segment_number,(strlen(current_omfsegment->segment_name)==0)?current_omfsegment->object_name:current_omfsegment->segment_name); + + /* Création du fichier Output */ + CreateOutputFile(param->output_file_path,current_omfsegment,current_omfproject); + } + } + + /* Libération mémoire : OMF Project + OMF Segment */ + mem_free_omfproject(current_omfproject); + my_Memory(MEMORY_SET_OMFSEGMENT,NULL,NULL,NULL); + my_File(FILE_FREE,NULL); + } + + /* Code Erreur */ + return(error); +} + + +/*********************************************************************************/ +/* Assemble65c816Segment() : Assemble des fichiers source 65c816 d'un Segment. */ +/*********************************************************************************/ +static int Assemble65c816Segment(struct omf_project *current_omfproject, struct omf_segment *current_omfsegment, char *macro_folder_path) +{ + int modified, error, first_time, has_error; + struct source_file *first_file; + struct source_line *current_line; + struct relocate_address *current_address; + struct relocate_address *next_address; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + my_Memory(MEMORY_FREE_EQUIVALENCE,NULL,NULL,current_omfsegment); + + /* Initialisation du compteur des labels uniques */ + GetUNID("INIT=1"); + + /* Récupère le répertoire des fichiers source */ + GetFolderFromPath(current_omfsegment->master_file_path,param->source_folder_path); + + /* Création des tables de recherche rapides */ + BuildReferenceTable(current_omfsegment); + + /** Chargement de tous les fichiers Source / Identifie les lignes en Commentaire + Vide **/ + printf(" o Loading Sources files...\n"); + LoadAllSourceFile(current_omfsegment->master_file_path,macro_folder_path,current_omfsegment); + + /** Chargement des fichiers Macro **/ + printf(" o Loading Macro files...\n"); + LoadSourceMacroFile(macro_folder_path,current_omfsegment); + + /** Recherche des Macro supplémentaires définies directement dans le Source **/ + GetMacroFromSource(current_omfsegment); + + /** Tri toutes les Macro **/ + my_Memory(MEMORY_SORT_MACRO,NULL,NULL,current_omfsegment); + + /** Recherche des Macro en double **/ + printf(" o Check for duplicated Macros...\n"); + CheckForDuplicatedMacro(current_omfsegment); + + /** Détermine le type des lignes (Code, Macro, Directive, Equivalence...) **/ + printf(" o Decoding lines types...\n"); + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + error = DecodeLineType(first_file->first_line,NULL,current_omfsegment,current_omfproject); + if(error) + return(1); + + /** Remplace les labels :locaux/]variable par un unid_ dans le Code et les Macros **/ + printf(" o Process local/variable Labels...\n"); + ProcessAllLocalLabel(current_omfsegment); + ProcessAllVariableLabel(current_omfsegment); + + /** Remplace les * par des Labels dans le Code et les Macros **/ + printf(" o Process Asterisk lines...\n"); + error = ProcessAllAsteriskLine(current_omfsegment); + if(error) + return(1); + + /** Création de la table des External **/ + printf(" o Build External table...\n"); + BuildExternalTable(current_omfsegment); + + /** Création de la table des Equivalences **/ + printf(" o Build Equivalence table...\n"); + BuildEquivalenceTable(current_omfsegment); + + /** Création de la table des variables ]LP **/ + printf(" o Build Variable table...\n"); + BuildVariableTable(current_omfsegment); + + /** Remplace les Equivalences **/ + printf(" o Process Equivalence values...\n"); + ProcessEquivalence(current_omfsegment); + + /** Remplace les Macro avec leur code **/ + printf(" o Replace Macros with Code...\n"); + error = ReplaceMacroWithContent(current_omfsegment,current_omfproject); + if(error) + return(1); + + /** Remplace les LUP par la séquence de code (cela vient après les Macro car le param de LUP peut être un des param d'appel de la Macro) **/ + printf(" o Replace Lup with code...\n"); + ReplaceLupWithCode(current_omfsegment); + + /** On refait les Equivalences, les Variables et les Remplacements dans le code amené par les Macro et les Loop **/ + BuildEquivalenceTable(current_omfsegment); + BuildVariableTable(current_omfsegment); + ProcessEquivalence(current_omfsegment); + + /** On va traiter les MX **/ + printf(" o Process MX directives...\n"); + ProcessMXDirective(current_omfsegment); + + /** On va traiter les Conditions **/ + printf(" o Process Conditional directives...\n"); + ProcessConditionalDirective(current_omfsegment); + + /** Création de la table des Labels **/ + printf(" o Build Label table...\n"); + BuildLabelTable(current_omfsegment); + + /** Recherche de Labels/Equivalence déclarés plusieurs fois **/ + printf(" o Check for duplicated Labels...\n"); + error = CheckForDuplicatedLabel(current_omfsegment); + if(error) + return(1); + + /** Détecte la liste des lignes inconnues **/ + printf(" o Check for unknown Source lines...\n"); + error = CheckForUnknownLine(current_omfsegment); + if(error) + return(1); + + /** Traite les lignes Dum **/ + printf(" o Check for Dum lines...\n"); + error = CheckForDumLine(current_omfsegment); + if(error) + return(1); + + /**** La détection automatique du Direct Page nous oblige à itérer plusieurs fois ****/ + first_time = 1; + modified = 1; + has_error = 0; + while(modified == 1 || has_error == 1) + { + /* Erreur lors de la génération du code */ + strcpy(param->buffer_latest_error,""); + has_error = 0; + + /*** Génération du code Opcode + Calcul de la Taille pour chaque ligne de Code ***/ + if(first_time) + printf(" o Compute Operand Code size...\n"); + BuildAllCodeLineSize(current_omfsegment); + + /*** Calcul de la taille pour chaque ligne de Data ***/ + if(first_time) + printf(" o Compute Operand Data size...\n"); + BuildAllDataLineSize(current_omfsegment); + + /*** Calcul les addresses de chaque ligne + Analyse les ORG / OBJ / REL / DUM ***/ + if(first_time) + printf(" o Compute Line address...\n"); + ComputeLineAddress(current_omfsegment,current_omfproject); + + /*** Génération du binaire pour les lignes Code (LINE_CODE) ***/ + if(first_time) + printf(" o Build Code Line...\n"); + BuildAllCodeLine(&has_error,current_omfsegment,current_omfproject); + + /** Compact Code for Direct Page (sauf si l'adresse est relogeable OMF ) **/ + if(first_time) + printf(" o Compact Code for Direct Page Lines...\n"); + modified = CompactDirectPageCode(current_omfsegment); + + /* Le compact de donne rien et on a une erreur => On sort */ + if(has_error == 1 && modified == 0) + my_RaiseError(ERROR_RAISE,param->buffer_latest_error); + + /** Il faut tout refaire => on va supprimer toutes les adresses à reloger **/ + if(modified == 1 || has_error == 1) + { + for(current_address=current_omfsegment->first_address; current_address; ) + { + next_address = current_address->next; + free(current_address); + current_address = next_address; + } + current_omfsegment->first_address = NULL; + current_omfsegment->last_address = NULL; + current_omfsegment->nb_address = 0; + } + + /* On a déjà fait un tour */ + first_time = 0; + } + + /** On va évaluer les lignes ERR **/ + printf(" o Check for Err lines...\n"); + error = CheckForErrLine(current_omfsegment); + if(error) + return(1); + + /** On va vérifier les adressages Page Direct **/ + printf(" o Check for Direct Page Lines...\n"); + error = CheckForDirectPageLine(current_omfsegment); + if(error) + return(1); + + /*** Génération du binaire pour les lignes Data (LINE_DATA) ***/ + printf(" o Build Data Line...\n"); + BuildAllDataLine(current_omfsegment); + + /** Create Object Code (LINE_CODE + LINE_DATA) **/ + printf(" o Build Object Code...\n"); + BuildObjectCode(current_omfsegment); + + /** Transforme les lignes directive avec Label en ligne Vide **/ + ProcessDirectiveWithLabelLine(current_omfsegment); + + /** Si on n'a pas de Segment Name ou de Load Name, on utilise les directive du Master Source **/ + if(current_omfsegment->segment_name == NULL) + current_omfsegment->segment_name = strdup(current_omfsegment->object_name); + if(current_omfsegment->load_name == NULL) + current_omfsegment->load_name = strdup(current_omfsegment->object_name); + if(current_omfsegment->segment_name == NULL || current_omfsegment->load_name == NULL) + { + printf(" => Error, Can't allocate memory...\n"); + return(1); + } + + /** Si on est en multi-segment Fixed, il faut faire remonter l'org address du segment **/ + if(current_omfproject->is_multi_fixed == 1) + { + /* On recherche la première ligne avec qqchise dedans */ + for(current_line=current_omfsegment->first_file->first_line; current_line; current_line=current_line->next) + if(current_line->nb_byte > 0) + { + current_omfsegment->org = current_line->address; + break; + } + } + + /* OK */ + return(0); +} + + +/*************************************************************************/ +/* Link65c816Segment() : Link les fichiers source 65c816 d'un Segment. */ +/*************************************************************************/ +static int Link65c816Segment(struct omf_project *current_omfproject, struct omf_segment *current_omfsegment) +{ + int nb_external; + struct label *external_label; + struct relocate_address *current_address; + struct omf_segment *external_omfsegment; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /** On va vérifier que tous les External utilisés de ce segments sont résolus **/ + my_Memory(MEMORY_GET_EXTERNAL_NB,&nb_external,NULL,current_omfsegment); + if(nb_external > 0) + { + /** On vérifie toutes les adresses relogeables **/ + for(current_address = current_omfsegment->first_address; current_address; current_address=current_address->next) + if(current_address->external != NULL) + if(current_address->external->external_segment == NULL) + { + /** On passe tous les Segments en revue pour trouver le label Global associé à ce External **/ + for(external_omfsegment = current_omfproject->first_segment; external_omfsegment; external_omfsegment = external_omfsegment->next) + { + /* Recherche un Label Global */ + my_Memory(MEMORY_SEARCH_LABEL,current_address->external->name,&external_label,external_omfsegment); + if(external_label != NULL) + if(external_label->is_global == 1) + { + /* Si on en a déjà trouvé un, c'est qu'il existe au moins 2 Label Global s'appelant pareil => Erreur */ + if(current_address->external->external_segment != NULL) + { + printf(" => Error : We have found 2 External Labels with the same name '%s' (File '%s', Line %d).\n",current_address->external->name,external_label->line->file->file_path,external_label->line->file_line_number); + return(1); + } + + /* On conserve celui là */ + current_address->external->external_segment = external_omfsegment; + current_address->external->external_label = external_label; + } + } + + /** On n'a pas pu trouver le Segment contenant ce Label externe :-( **/ + if(current_address->external->external_segment == NULL) + { + printf(" => Error : Can't find External Label named '%s' (File '%s', Line %d).\n",current_address->external->name,current_address->external->source_line->file->file_path,current_address->external->source_line->file_line_number); + return(1); + } + } + } + + /** Taille du Body du Segment (on prend plus large pour l'OMF) **/ + if(current_omfproject->is_multi_fixed == 1) + current_omfsegment->segment_body_length = current_omfsegment->object_length; + else + current_omfsegment->segment_body_length = 1024 + current_omfsegment->object_length + CRECORD_SIZE*current_omfsegment->nb_address + END_SIZE; + + /** Allocation mémoire Segment Body **/ + current_omfsegment->segment_body_file = (unsigned char *) calloc(current_omfsegment->segment_body_length,sizeof(unsigned char)); + if(current_omfsegment->segment_body_file == NULL) + { + printf(" => Error : Can't allocate memory to build Body File buffer.\n"); + return(1); + } + + /** Création du Segment Body **/ + if(current_omfproject->is_multi_fixed == 1) + { + /* Reloge les adresses externes fixed */ + RelocateExternalFixedAddress(current_omfproject,current_omfsegment); + + /* Conserve le code objet */ + memcpy(current_omfsegment->segment_body_file,current_omfsegment->object_code,current_omfsegment->object_length); + } + else + current_omfsegment->body_length = BuildOMFBody(current_omfproject,current_omfsegment); + + /* Création du Segment Header */ + if(current_omfproject->is_multi_fixed == 1) + current_omfsegment->header_length = 0; + else + current_omfsegment->header_length = BuildOMFHeader(current_omfproject,current_omfsegment); + + /* OK */ + return(0); +} + + +/************************************************************************/ +/* IsLinkFile() : Détermine si un fichier Source est un fichier Link. */ +/************************************************************************/ +static int IsLinkFile(struct source_file *master_file) +{ + int i, found; + struct source_line *current_line; + char *opcode_link[] = {"DSK","TYP","AUX","XPL","ASM","DS","KND","ALI","LNA","SNA","ORG","BSZ",NULL}; /* Opcode exclusifs au fichier Link */ + + /* Fichier vide ? */ + if(master_file->first_line == NULL) + return(0); + + /** On passe toutes les lignes en revue **/ + for(current_line = master_file->first_line; current_line; current_line = current_line->next) + { + /* Commentaire / Vide */ + if(current_line->type == LINE_COMMENT || current_line->type == LINE_EMPTY) + continue; + + /* Reconnait les Opcode du Link */ + for(i=0,found=0; opcode_link[i]!=NULL; i++) + if(!my_stricmp(current_line->opcode_txt,opcode_link[i])) + { + found = 1; + break; + } + if(found == 0) + return(0); + } + + /* OK */ + return(1); +} + + +/************************************************************/ +/* BuildSingleSegment() : Création d'un OMF mono-Segment. */ +/************************************************************/ +static struct omf_project *BuildSingleSegment(char *master_file_path) +{ + struct omf_project *current_omfproject; + + /* OMF Header */ + current_omfproject = (struct omf_project *) calloc(1,sizeof(struct omf_project)); + if(current_omfproject == NULL) + return(NULL); + + /** OMF Segment **/ + current_omfproject->nb_segment = 1; + current_omfproject->first_segment = mem_alloc_omfsegment(); + if(current_omfproject->first_segment == NULL) + { + mem_free_omfproject(current_omfproject); + return(NULL); + } + current_omfproject->first_segment->master_file_path = strdup(master_file_path); + if(current_omfproject->first_segment->master_file_path == NULL) + { + mem_free_omfproject(current_omfproject); + return(NULL); + } + + /* En mono-Segment, il n'y a pas d'ExpressLoad, le premier segment a le numéro 1 */ + current_omfproject->first_segment->segment_number = 1; + + /* Renvoi la structure */ + return(current_omfproject); +} + + +/*************************************************************/ +/* BuildLinkFile() : Récupère les données du fichier Link. */ +/*************************************************************/ +static struct omf_project *BuildLinkFile(struct source_file *link_file) +{ + struct omf_project *current_omfproject; + struct omf_segment *new_omfsegment; + struct omf_segment *current_omfsegment; + struct source_line *current_line; + int i; + char **dsk_name_tab; + DWORD *org_address_tab; + DWORD *file_size_tab; + char file_path[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Allocation mmoire OMF Heaer */ + current_omfproject = (struct omf_project *) calloc(1,sizeof(struct omf_project)); + if(current_omfproject == NULL) + { + printf(" => Error, Impossible to allocate memory to process Link file.\n"); + return(NULL); + } + + /* Valeurs par défaut */ + current_omfproject->type = 0xB3; /* GS/OS Application */ + current_omfproject->aux_type = 0x0000; + + /*****************************************************/ + /*** Passe toutes les lignes du Link File en revue ***/ + /*****************************************************/ + for(current_line = link_file->first_line; current_line; current_line = current_line->next) + { + /* Commentaire / Vide */ + if(current_line->type == LINE_COMMENT || current_line->type == LINE_EMPTY) + continue; + + /********************/ + /** Nouveau Header **/ + /********************/ + /** TYP : Type du fchier **/ + if(!my_stricmp(current_line->opcode_txt,"TYP")) + { + /* Décode la valeur */ + current_omfproject->type = GetByteValue(current_line->operand_txt); + continue; + } + + /** AUX : AuxType du fichier **/ + if(!my_stricmp(current_line->opcode_txt,"AUX")) + { + /* Décode la valeur */ + current_omfproject->aux_type = GetWordValue(current_line->operand_txt); + continue; + } + + /** XPL : Express Load **/ + if(!my_stricmp(current_line->opcode_txt,"XPL")) + { + current_omfproject->express_load = 1; + continue; + } + + /**********************************/ + /** DSK : Nouveau Projet/Fichier **/ + /**********************************/ + if(!my_stricmp(current_line->opcode_txt,"DSK")) + { + /*** Table des nom de fichier + Table des ORG ***/ + /* Allocation */ + dsk_name_tab = (char **) calloc(current_omfproject->nb_file+1,sizeof(char *)); + if(dsk_name_tab == NULL) + { + printf(" => Error, Impossible to allocate memory to process Link file.\n"); + mem_free_omfproject(current_omfproject); + return(NULL); + } + org_address_tab = (DWORD *) calloc(current_omfproject->nb_file+1,sizeof(DWORD)); + if(org_address_tab == NULL) + { + printf(" => Error, Impossible to allocate memory to process Link file.\n"); + free(dsk_name_tab); + mem_free_omfproject(current_omfproject); + return(NULL); + } + file_size_tab = (DWORD *) calloc(current_omfproject->nb_file+1,sizeof(DWORD)); + if(file_size_tab == NULL) + { + printf(" => Error, Impossible to allocate memory to process Link file.\n"); + free(dsk_name_tab); + free(org_address_tab); + mem_free_omfproject(current_omfproject); + return(NULL); + } + /* Remplissage */ + for(i=0; inb_file; i++) + { + dsk_name_tab[i] = current_omfproject->dsk_name_tab[i]; + org_address_tab[i] = current_omfproject->org_address_tab[i]; + } + /* Remplacement */ + if(current_omfproject->dsk_name_tab != NULL) + free(current_omfproject->dsk_name_tab); + current_omfproject->dsk_name_tab = dsk_name_tab; + if(current_omfproject->org_address_tab != NULL) + free(current_omfproject->org_address_tab); + current_omfproject->org_address_tab = org_address_tab; + if(current_omfproject->file_size_tab != NULL) + free(current_omfproject->file_size_tab); + current_omfproject->file_size_tab = file_size_tab; + + /* Un fichier de plus */ + current_omfproject->nb_file++; + + /* Nouvelles valeurs */ + current_omfproject->org_address_tab[current_omfproject->nb_file-1] = 0xFFFFFFFF; + current_omfproject->dsk_name_tab[current_omfproject->nb_file-1] = strdup(current_line->operand_txt); + if(current_omfproject->dsk_name_tab[current_omfproject->nb_file-1] == NULL) + { + printf(" => Error, Impossible to allocate memory to process Link file.\n"); + mem_free_omfproject(current_omfproject); + return(NULL); + } + + /* Ligne suivante */ + continue; + } + + /** ORG : Adresse d'assemblage du fichier Fixed Address **/ + if(!my_stricmp(current_line->opcode_txt,"ORG") && current_omfproject->nb_file > 0) + { + /* Décode la valeur */ + current_omfproject->org_address_tab[current_omfproject->nb_file-1] = GetDwordValue(current_line->operand_txt); + + /* Vérfie la plage */ + if(current_omfproject->org_address_tab[current_omfproject->nb_file-1] > 0xFFFFFF) + { + printf(" => Error, Invalid ORG value : %X.\n",(int)current_omfproject->org_address_tab[current_omfproject->nb_file-1]); + mem_free_omfproject(current_omfproject); + return(NULL); + } + continue; + } + + + /***************************/ + /** ASM : Nouveau Segment **/ + /***************************/ + if(!my_stricmp(current_line->opcode_txt,"ASM")) + { + /* Allocation mémoire du Segment */ + new_omfsegment = mem_alloc_omfsegment(); + if(new_omfsegment == NULL) + { + printf(" => Error, Impossible to allocate memory to process Link file.\n"); + mem_free_omfproject(current_omfproject); + return(NULL); + } + + /* Nom du fichier Source */ + BuildAbsolutePath(current_line->operand_txt,param->current_folder_path,file_path); + new_omfsegment->master_file_path = strdup(file_path); + if(new_omfsegment->master_file_path == NULL) + { + printf(" => Error, Impossible to allocate memory to process Link file.\n"); + mem_free_omfproject(current_omfproject); + return(NULL); + } + + /* Numéro du fichier */ + new_omfsegment->file_number = current_omfproject->nb_file; + + /* Attachement du Segment à la liste */ + if(current_omfproject->first_segment == NULL) + current_omfproject->first_segment = new_omfsegment; + else + current_omfproject->last_segment->next = new_omfsegment; + current_omfproject->last_segment = new_omfsegment; + current_omfproject->nb_segment++; + + /* Ligne suivante */ + continue; + } + + /** DS : Nombre de 0 à ajouter à la fin du segment **/ + if(!my_stricmp(current_line->opcode_txt,"DS") && current_omfproject->last_segment != NULL) + { + current_omfproject->last_segment->ds_end = atoi(current_line->operand_txt); + continue; + } + + /** KND : Type et Attributs du Segment **/ + if(!my_stricmp(current_line->opcode_txt,"KND") && current_omfproject->last_segment != NULL) + { + /* Décode la valeur */ + current_omfproject->last_segment->type_attributes = GetWordValue(current_line->operand_txt); + + /* Vérifie les valeurs : Type */ + if(!(((current_omfproject->last_segment->type_attributes & 0x00FF) == 0x0000) || + ((current_omfproject->last_segment->type_attributes & 0x00FF) == 0x0001) || + ((current_omfproject->last_segment->type_attributes & 0x00FF) == 0x0002) || + ((current_omfproject->last_segment->type_attributes & 0x00FF) == 0x0004) || + ((current_omfproject->last_segment->type_attributes & 0x00FF) == 0x0008) || + ((current_omfproject->last_segment->type_attributes & 0x00FF) == 0x0010) || + ((current_omfproject->last_segment->type_attributes & 0x00FF) == 0x0012))) + { + printf(" => Error, Invalid Link file : Unknown Type value for Directive KND (%04X) at line %d.\n",current_omfproject->last_segment->type_attributes,current_line->file_line_number); + mem_free_omfproject(current_omfproject); + return(NULL); + } + + /* Valeur suivante */ + continue; + } + + /** ALI : Alignement **/ + if(!my_stricmp(current_line->opcode_txt,"ALI") && current_omfproject->last_segment != NULL) + { + if(!my_stricmp(current_line->operand_txt,"BANK")) + current_omfproject->last_segment->alignment = ALIGN_BANK; + else if(!my_stricmp(current_line->operand_txt,"PAGE")) + current_omfproject->last_segment->alignment = ALIGN_PAGE; + else if(!my_stricmp(current_line->operand_txt,"NONE")) + current_omfproject->last_segment->alignment = ALIGN_NONE; + else + { + printf(" => Error, Invalid Link file : Unknown value for Directive ALI (%s) at line %d.\n",current_line->operand_txt,current_line->file_line_number); + mem_free_omfproject(current_omfproject); + return(NULL); + } + + /* Ligne suivante */ + continue; + } + + /** LNA : Load Name **/ + if(!my_stricmp(current_line->opcode_txt,"LNA") && current_omfproject->last_segment != NULL) + { + if(current_omfproject->last_segment->load_name == NULL) + { + current_omfproject->last_segment->load_name = strdup(current_line->operand_txt); + if(current_omfproject->last_segment->load_name == NULL) + { + printf(" => Error, Impossible to allocate memory to process Link file.\n"); + mem_free_omfproject(current_omfproject); + return(NULL); + } + + /* Enlève les " ou ' */ + CleanUpName(current_omfproject->last_segment->load_name); + } + else + { + /* On a déjà un LNA */ + if(!my_stricmp(current_omfproject->last_segment->load_name,current_line->operand_txt)) + continue; /* Même valeur, on ne dit rien */ + else + { + printf(" => Error, Invalid Link file : Two LNA directives found for Segment '%s'.\n",current_omfproject->last_segment->master_file_path); + mem_free_omfproject(current_omfproject); + return(NULL); + } + } + + /* Ligne suivante */ + continue; + } + + /** SNA : Segment Name **/ + if(!my_stricmp(current_line->opcode_txt,"SNA") && current_omfproject->last_segment != NULL) + { + if(current_omfproject->last_segment->segment_name == NULL) + { + current_omfproject->last_segment->segment_name = strdup(current_line->operand_txt); + if(current_omfproject->last_segment->segment_name == NULL) + { + printf(" => Error, Impossible to allocate memory to process Link file.\n"); + mem_free_omfproject(current_omfproject); + return(NULL); + } + + /* Enlève les " ou ' */ + CleanUpName(current_omfproject->last_segment->segment_name); + } + else + { + /* On a déjà un SNA */ + if(!my_stricmp(current_omfproject->last_segment->segment_name,current_line->operand_txt)) + continue; /* Même valeur, on ne dit rien */ + else + { + printf(" => Error, Invalid Link file : Two SNA directives found for Segment '%s'.\n",current_omfproject->last_segment->master_file_path); + mem_free_omfproject(current_omfproject); + return(NULL); + } + } + + /* Ligne suivante */ + continue; + } + + /** La commande est reconnue, mais on n'a pas de Segment comme support **/ + if(current_omfproject->last_segment == NULL && + (!my_stricmp(current_line->opcode_txt,"DS") || !my_stricmp(current_line->opcode_txt,"KND") || !my_stricmp(current_line->opcode_txt,"ALI") || + !my_stricmp(current_line->opcode_txt,"LNA") || !my_stricmp(current_line->opcode_txt,"SNA"))) + { + printf(" => Error, The directive %s is valid but a previous directive ASM is missing in the Link file.\n",current_line->opcode_txt); + mem_free_omfproject(current_omfproject); + return(NULL); + } + + /** Commande inconnue **/ + printf(" => Error, Invalid Link file : Unknown directive found (%s) at line %d.\n",current_line->opcode_txt,current_line->file_line_number); + mem_free_omfproject(current_omfproject); + return(NULL); + } + + /****************************************************************************/ + /** On valide les valeurs du Header, des Projects/Fichiers et des Segments **/ + /****************************************************************************/ + /* A t'on un Multi-Segment non OMF */ + if(current_omfproject->type == 0x0006) /* BIN = Fixed Address : MultiBinary or SingleBinary */ + { + if(current_omfproject->dsk_name_tab != NULL) + { + /** Single Binary : Tous les Segments seront collés les uns derrière les autres, dans 1 ou plusieurs fichiers **/ + current_omfproject->is_omf = 0; + current_omfproject->is_multi_fixed = 1; + current_omfproject->is_single_binary = 1; + current_omfproject->express_load = 0; + + /* Vérifie les Noms */ + for(i=0; inb_file; i++) + { + if(IsProdosName(current_omfproject->dsk_name_tab[i]) == 0) + { + printf(" => Error, Bad Link file name '%s' : Invalid Prodos file name (15 chars max, letters/numbers/. allowed).\n",current_omfproject->dsk_name_tab[i]); + mem_free_omfproject(current_omfproject); + return(NULL); + } + } + + /* Vérifie les Org Address */ + for(i=0; inb_file; i++) + { + if(current_omfproject->org_address_tab[i] == 0xFFFFFFFF) + { + printf(" => Error, Invalid Link file : Directive ORG is missing for File #%d.\n",i+1); + mem_free_omfproject(current_omfproject); + return(NULL); + } + } + } + else if(current_omfproject->dsk_name_tab == NULL) /* Pas de DSK ni de ORG dans le Header */ + { + /** Multi Binary : On va générer autant de fichier Binary qu'il y a de Segments **/ + current_omfproject->is_omf = 0; + current_omfproject->is_multi_fixed = 1; + current_omfproject->is_single_binary = 0; + current_omfproject->express_load = 0; + } + } + else + { + /** OMF : On va générer un Program Relogeable OMF v2.1 **/ + current_omfproject->is_omf = 1; + current_omfproject->is_multi_fixed = 0; + current_omfproject->is_single_binary = 0; + + /** On élimine les cas douteux **/ + if(current_omfproject->nb_file > 1) + { + printf(" => Error, Invalid Link file : Too many DSK directives (only one for an OMF File).\n"); + mem_free_omfproject(current_omfproject); + return(NULL); + } + if(current_omfproject->dsk_name_tab == NULL) + { + printf(" => Error, Invalid Link file : Directive DSK is missing (Target OMF File name).\n"); + mem_free_omfproject(current_omfproject); + return(NULL); + } + if(current_omfproject->org_address_tab[0] != 0xFFFFFFFF) + { + printf(" => Error, Invalid Link file : Directive ORG is not allowed (Target is a Relocatable OMF File).\n"); + mem_free_omfproject(current_omfproject); + return(NULL); + } + + /* Vérifie le nom de fichier */ + if(IsProdosName(current_omfproject->dsk_name_tab[0]) == 0) + { + printf(" => Error, Bad Link file name '%s' : Invalid Prodos file name (15 chars max, letters/numbers/. allowed).\n",current_omfproject->dsk_name_tab[0]); + mem_free_omfproject(current_omfproject); + return(NULL); + } + } + + /** Segments **/ + if(current_omfproject->nb_segment == 0) + { + printf(" => Error, Invalid Link file : No Segment defined (use ASM directive).\n"); + mem_free_omfproject(current_omfproject); + return(NULL); + } + + /** Vérifie tous les Segments :on met une chaine vide pour les paramètres manquant **/ + for(current_omfsegment = current_omfproject->first_segment; current_omfsegment; current_omfsegment=current_omfsegment->next) + { + /* Load Name */ + if(current_omfsegment->load_name == NULL) + { + current_omfsegment->load_name = strdup(""); + if(current_omfsegment->load_name == NULL) + { + printf(" => Error, Impossible to allocate memory to process Link file.\n"); + mem_free_omfproject(current_omfproject); + return(NULL); + } + } + + /* Segment Name */ + if(current_omfsegment->segment_name == NULL) + { + current_omfsegment->segment_name = strdup(""); + if(current_omfsegment->segment_name == NULL) + { + printf(" => Error, Impossible to allocate memory to process Link file.\n"); + mem_free_omfproject(current_omfproject); + return(NULL); + } + } + } + + /* OK */ + return(current_omfproject); +} + +/***********************************************************************/ diff --git a/Source/a65816_Link.h b/Source/a65816_Link.h new file mode 100644 index 0000000..671f5bd --- /dev/null +++ b/Source/a65816_Link.h @@ -0,0 +1,11 @@ +/***********************************************************************/ +/* */ +/* a65816_Link.h : Header d'Assemblage / Linkage d'un source 65c816. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +int AssembleLink65c816(char *,char *,int); + +/***********************************************************************/ diff --git a/Source/a65816_Lup.c b/Source/a65816_Lup.c new file mode 100644 index 0000000..91435f2 --- /dev/null +++ b/Source/a65816_Lup.c @@ -0,0 +1,528 @@ +/***********************************************************************/ +/* */ +/* a65816_Lup.c : Module pour la gestion des Lup. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Dc_Library.h" +#include "a65816_File.h" +#include "a65816_Line.h" +#include "a65816_Lup.h" + +static struct source_line *BuildLupLine(struct source_line *,struct source_line *,struct omf_segment *); +static struct source_line *BuildSourceLupOneIterationLine(struct source_line *,struct source_line *,int,struct omf_segment *); +static struct source_line *BuildSourceLupLine(struct source_line *,int,struct omf_segment *); + +/************************************************************/ +/* ReplaceLupWithCode() : Remplace les Lup par leur code. */ +/************************************************************/ +int ReplaceLupWithCode(struct omf_segment *current_omfsegment) +{ + BYTE byte_count, bit_shift; + WORD offset_reference; + DWORD address_long; + int is_reloc; + int64_t value; + struct source_file *first_file; + struct source_line *begin_line; + struct source_line *end_line; + struct source_line *first_lup_line; + struct source_line *last_lup_line; + struct variable *current_variable; + struct external *current_external; + char buffer_error[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Récupère le 1er fichier source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + if(first_file == NULL) + return(0); + + /*** Passe en revue toutes les lignes ***/ + for(begin_line=first_file->first_line; begin_line; begin_line=begin_line->next) + { + /* On ignore les lignes non valides */ + if(begin_line->is_valid == 0) + continue; + + /** On va devoir gérer les variables en dehors de Lup pour calculer leur valeur **/ + if(begin_line->type == LINE_VARIABLE) + { + /* Récupère la variable */ + my_Memory(MEMORY_SEARCH_VARIABLE,begin_line->label_txt,¤t_variable,current_omfsegment); + if(current_variable == NULL) + { + /* Erreur : On commence une nouvelle alors que la précédente n'est pas terminé */ + sprintf(param->buffer_error,"Impossible to locate Variable '%s' (line %d from file '%s')",begin_line->label_txt,begin_line->file_line_number,begin_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Calcule sa nouvelle valeur */ + value = EvalExpressionAsInteger(begin_line->operand_txt,buffer_error,begin_line,begin_line->nb_byte-1,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) > 0) + { + /* Erreur : On commence une nouvelle alors que la précédente n'est pas terminé */ + sprintf(param->buffer_error,"Impossible to evaluate Variable '%s' value '%s' (line %d from file '%s')",begin_line->label_txt,begin_line->operand_txt,begin_line->file_line_number,begin_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Stocke la valeur */ + current_variable->value = value; + } + + /** Recherche les appels de Lup (dans le code, pas dans le corps des Macro présentes dans le code) **/ + if(begin_line->type == LINE_DIRECTIVE && begin_line->is_inside_macro == 0 && !my_stricmp(begin_line->opcode_txt,"LUP")) + { + /** Recherche la fin de la Lup **/ + for(end_line=begin_line->next; end_line; end_line=end_line->next) + { + /* On ignore les lignes non valides */ + if(end_line->is_valid == 0) + continue; + + if(end_line->type == LINE_DIRECTIVE && !my_stricmp(end_line->opcode_txt,"--^")) + break; + else if(end_line->type == LINE_DIRECTIVE && !my_stricmp(end_line->opcode_txt,"LUP")) + { + /* Erreur : On commence une nouvelle alors que la précédente n'est pas terminé */ + sprintf(param->buffer_error,"Impossible to locate end of Lup '--^', line %d from file '%s'",begin_line->file_line_number,begin_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + } + + /* Rien trouvé ? */ + if(end_line == NULL) + { + sprintf(param->buffer_error,"Impossible to locate end of Lup '--^', line %d from file '%s'",begin_line->file_line_number,begin_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /** Construit les lignes de codes de cette Lup (on remplace les labels par des nouveaux) **/ + first_lup_line = BuildLupLine(begin_line,end_line,current_omfsegment); + if(first_lup_line == NULL) + { + /* Rien à insérer : Ligne suivante */ + begin_line = end_line; + } + else + { + /* Dernière ligne de la Lup */ + for(last_lup_line = first_lup_line; last_lup_line->next != NULL; last_lup_line=last_lup_line->next) + ; + + /** Insère les lignes de Code derrière la fin de la Lup **/ + last_lup_line->next = end_line->next; + end_line->next = first_lup_line; + + /* Ligne suivante */ + begin_line = last_lup_line; + } + } + } + + /* OK */ + return(0); +} + + +/*****************************************************************/ +/* BuildLupLine() : Construction des lignes de code de la Lup. */ +/*****************************************************************/ +static struct source_line *BuildLupLine(struct source_line *begin_line, struct source_line *end_line, struct omf_segment *current_omfsegment) +{ + int64_t nb_iter_64; + BYTE byte_count, bit_shift; + WORD offset_reference; + DWORD address_long; + char *new_label; + int i, nb_iter, is_reloc; + struct source_line *first_line = NULL; + struct source_line *last_line = NULL; + struct source_line *first_new_line; + struct source_line *last_new_line; + struct source_line *label_line; + struct source_line *current_line; + struct external *current_external; + char buffer_error[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /** Décodage du nombre de tour **/ + if(strlen(begin_line->operand_txt) == 0) + nb_iter_64 = 0; /* On a un PB car on a un LUP mais sans Nb, on va donc considérer qu'on LOOP 0 fois (arrive dans le cas de Macro avec paramètres variables) */ + else + { + nb_iter_64 = EvalExpressionAsInteger(begin_line->operand_txt,buffer_error,begin_line,begin_line->nb_byte-1,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Impossible to get Lup value '%s' (line %d from file '%s') : %s",begin_line->operand_txt,begin_line->file_line_number,begin_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + } + + /* Il n'y aura pas d'itération */ + if(nb_iter_64 <= 0 || nb_iter_64 > 0x8000) + { + /* Aucun Label à gérer, on sort */ + if(strlen(begin_line->label_txt) == 0 && strlen(end_line->label_txt) == 0) + return(NULL); + + /* On va devoir créer des Lignes vides pour héberger les Labels */ + if(strlen(begin_line->label_txt) > 0) + { + /* On va devoir créer une ligne vide pour héberger le label du début */ + label_line = BuildEmptyLabelLine(begin_line->label_txt,begin_line); + if(label_line == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to process line (line %d from file '%s')",begin_line->file_line_number,begin_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Ajoute la ligne */ + first_line = label_line; + last_line = label_line; + } + if(strlen(end_line->label_txt) > 0) + { + /* On va devoir créer une ligne vide pour héberger le label de fin */ + label_line = BuildEmptyLabelLine(end_line->label_txt,end_line); + if(label_line == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to process line (line %d from file '%s')",end_line->file_line_number,end_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Met la ligne contenant le label de fin en deuxième position */ + if(first_line == NULL) + first_line = label_line; + else + last_line->next = label_line; + last_line = label_line; + } + + /* Renvoi les lignes Label */ + return(first_line); + } + nb_iter = (int) nb_iter_64; + + /*** On va produire les X itérations de code ***/ + for(i=0; inext) + if(current_line->next == NULL) + last_new_line = current_line; + + /* Attache les lignes aux précédentes */ + if(first_line == NULL) + first_line = first_new_line; + else + last_line->next = first_new_line; + last_line = last_new_line; + } + + /** Il y a un label sur la ligne du LUP **/ + if(strlen(begin_line->label_txt) > 0) + { + /* On essaye de le placer sur la 1ère ligne des lignes de substitution */ + if(strlen(first_line->label_txt) == 0) + { + new_label = strdup(begin_line->label_txt); + if(new_label == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to process line (line %d from file '%s')",begin_line->file_line_number,begin_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + free(first_line->label_txt); + first_line->label_txt = new_label; + } + else + { + /* On va devoir créer une ligne vide pour héberger le label */ + label_line = BuildEmptyLabelLine(begin_line->label_txt,first_line); + if(label_line == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to process line (line %d from file '%s')",begin_line->file_line_number,begin_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Met la ligne avant toutes les autres */ + label_line->next = first_line; + first_line = label_line; + } + } + + /** Il y a un label sur la ligne du --^ **/ + if(strlen(end_line->label_txt) > 0) + { + /* On essaye de le placer sur la dernière ligne des lignes de substitution */ + if(strlen(last_line->label_txt) == 0) + { + new_label = strdup(end_line->label_txt); + if(new_label == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to process line (line %d from file '%s')",begin_line->file_line_number,begin_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + free(last_line->label_txt); + last_line->label_txt = new_label; + } + else + { + /* On va devoir créer une ligne vide pour héberger le label */ + label_line = BuildEmptyLabelLine(end_line->label_txt,last_line); + if(label_line == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to process line (line %d from file '%s')",end_line->file_line_number,end_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Met la ligne après toutes les autres */ + last_line->next = label_line; + last_line = label_line; + } + } + + /* Renvoi la liste des instructions générées */ + return(first_line); +} + + +/********************************************************************************************************/ +/* BuildSourceLupOneIterationLine() : Construction des ligne de Source provenant d'une boucle de Lup. */ +/********************************************************************************************************/ +static struct source_line *BuildSourceLupOneIterationLine(struct source_line *begin_line, struct source_line *end_line, int iter, struct omf_segment *current_omfsegment) +{ + int is_reloc; + int64_t value; + BYTE byte_count, bit_shift; + WORD offset_reference; + DWORD address_long; + char *new_operand; + struct source_line *current_line; + struct source_line *new_line; + struct source_line *first_line = NULL; + struct source_line *last_line = NULL; + struct source_line *label_line; + struct variable *current_variable; + struct external *current_external; + char label_unique[512]; + char buffer_error[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /*** La première ligne est le LUP, la dernière est le --^ ***/ + for(current_line = begin_line->next; current_line != end_line; current_line = current_line->next) + { + /** Ligne de code / data / directive (on exclu les Global) **/ + if(current_line->type == LINE_CODE || current_line->type == LINE_EMPTY || current_line->type == LINE_DATA || + current_line->type == LINE_DIRECTIVE || current_line->type == LINE_MACRO) + { + /** On va dupliquer la ligne en adaptant le Label et l'Operande **/ + new_line = BuildSourceLupLine(current_line,iter,current_omfsegment); /* iter : 1 -> nb_iter */ + + /* Ajoute cette ligne à la liste */ + if(first_line == NULL) + first_line = new_line; + else + last_line->next = new_line; + last_line = new_line; + } + /** Variable **/ + else if(current_line->type == LINE_VARIABLE) + { + /** Met à jour la valeur de la variable **/ + /* Récupère la variable */ + my_Memory(MEMORY_SEARCH_VARIABLE,current_line->label_txt,¤t_variable,current_omfsegment); + if(current_variable == NULL) + { + sprintf(param->buffer_error,"Impossible to find Variable '%s' declaration (line %d from file '%s') : %s",current_line->label_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Calcule sa nouvelle valeur */ + value = EvalExpressionAsInteger(current_line->operand_txt,buffer_error,current_line,current_line->nb_byte-1,&is_reloc,&byte_count,&bit_shift,&offset_reference,&address_long,¤t_external,current_omfsegment); + if(strlen(buffer_error) > 0) + { + sprintf(param->buffer_error,"Impossible to evaluate Variable '%s' value '%s' (line %d from file '%s') : %s",current_line->label_txt,current_line->operand_txt,current_line->file_line_number,current_line->file->file_name,buffer_error); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Stocke la valeur */ + current_variable->value = value; + } + } + + /*** On va modifier les Labels Globaux pour obtenir qqchose d'unique ***/ + for(current_line=first_line; current_line; current_line=current_line->next) + { + /* On ne va traiter que les Labels globaux */ + if(strlen(current_line->label_txt) > 0 && current_line->label_txt[0] != ':' && current_line->label_txt[0] != ']') + { + /* Création d'un label unique */ + GetUNID(&label_unique[0]); + + /** On passe toutes les lignes en revue **/ + for(label_line=first_line; label_line; label_line=label_line->next) + { + /** Remplace le Label dans l'Operand **/ + new_operand = ReplaceInOperand(label_line->operand_txt,current_line->label_txt,label_unique,SEPARATOR_REPLACE_VARIABLE,label_line); + if(new_operand != label_line->operand_txt) + { + free(label_line->operand_txt); + label_line->operand_txt = new_operand; + } + } + + /* On le remplace dans la ligne l'ayant définie */ + free(current_line->label_txt); + current_line->label_txt = strdup(label_unique); + if(current_line->label_txt == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to replace Lup at line %d from file '%s' [Update Label]",begin_line->file_line_number,begin_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + } + } + + /* Renvoie cet ensemble de lignes */ + return(first_line); +} + + +/************************************************************************************/ +/* BuildSourceLupLine() : Construction d'une ligne de Source provenant d'une Lup. */ +/************************************************************************************/ +static struct source_line *BuildSourceLupLine(struct source_line *current_source_line, int iter, struct omf_segment *current_omfsegment) +{ + int i, j, k, l; + struct source_line *new_source_line = NULL; + char new_operand_txt[1024]; + char value_txt[256]; + char variable_name[1024]; + struct variable *current_variable; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Allocation de la nouvelle ligne */ + new_source_line = (struct source_line *) calloc(1,sizeof(struct source_line)); + if(new_source_line == NULL) + return(NULL); + + /** Transfert les caractéristiques de la ligne Source (numéro de la ligne...) **/ + new_source_line->file_line_number = current_source_line->file_line_number; + new_source_line->file = current_source_line->file; + new_source_line->type = current_source_line->type; + new_source_line->no_direct_page = current_source_line->no_direct_page; + new_source_line->address = -1; + new_source_line->nb_byte = -1; + new_source_line->is_valid = 1; /* la ligne est valide */ + strcpy(new_source_line->m,"?"); + strcpy(new_source_line->x,"?"); + strcpy(new_source_line->reloc," "); + new_source_line->operand_value = 0xFFFFFFFF; + new_source_line->operand_address_long = 0xFFFFFFFF; + new_source_line->macro = current_source_line->macro; + + /** On duplique les premiers éléments **/ + new_source_line->label_txt = strdup(current_source_line->label_txt); + new_source_line->opcode_txt = strdup(current_source_line->opcode_txt); + new_source_line->comment_txt = strdup(current_source_line->comment_txt); + if(new_source_line->label_txt == NULL || new_source_line->opcode_txt == NULL || new_source_line->comment_txt == NULL) + { + mem_free_sourceline(new_source_line); + sprintf(param->buffer_error,"Impossible to allocate memory to process Lup at line %d from file '%s'",current_source_line->file_line_number,current_source_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /** On modifie le Label : @ -> ASC iter **/ + for(i=0; i<(int)strlen(new_source_line->label_txt); i++) + if(new_source_line->label_txt[i] == '@') + { + if(iter > 26) + { + mem_free_sourceline(new_source_line); + sprintf(param->buffer_error,"Impossible to update Label '%s' (iter=%d > 26) in Lup at line %d from file '%s'",current_source_line->label_txt,iter+1,current_source_line->file_line_number,current_source_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + else + new_source_line->label_txt[i] = 'A' + iter - 1; /* A-Z */ + } + + /** On effectue les remplacements de variables dans l'Operande **/ + for(i=0,l=0; i<(int)strlen(current_source_line->operand_txt); i++) + { + if(current_source_line->operand_txt[i] == ']') + { + /* Isole le nom de la variable */ + variable_name[0] = ']'; + for(j=i+1,k=1; j<(int)strlen(current_source_line->operand_txt); j++) + if(IsSeparator(current_source_line->operand_txt[j],0)) + break; + else + variable_name[k++] = current_source_line->operand_txt[j]; + variable_name[k] = '\0'; + + /* Recherche la variable */ + my_Memory(MEMORY_SEARCH_VARIABLE,variable_name,¤t_variable,current_omfsegment); + if(current_variable == NULL) + { + mem_free_sourceline(new_source_line); + sprintf(param->buffer_error,"Impossible to find Lup Variable '%s' declaration (line %d from file '%s')",current_source_line->label_txt,current_source_line->file_line_number,current_source_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Place la valeur sous la bonne forme : Les valeurs des variables sont limitées à 32 bits */ + if(current_variable->is_dollar) + sprintf(value_txt,"$%X",(int)current_variable->value); + else if(current_variable->is_pound_dollar) + sprintf(value_txt,"#$%X",(int)current_variable->value); + else if(current_variable->is_pound) + sprintf(value_txt,"#%d",(int)current_variable->value); + else + sprintf(value_txt,"%d",(int)current_variable->value); + strcpy(&new_operand_txt[l],value_txt); + l += (int) strlen(value_txt); + + /* On continue d'explorer l'operand */ + i += (int) (strlen(variable_name) - 1); /* i++ */ + } + else + new_operand_txt[l++] = current_source_line->operand_txt[i]; + } + new_operand_txt[l] = '\0'; + + /* Allocation mémoire */ + new_source_line->operand_txt = strdup(new_operand_txt); + if(new_source_line->operand_txt == NULL) + { + mem_free_sourceline(new_source_line); + sprintf(param->buffer_error,"Impossible to allocate memory to process Lup at line %d from file '%s'",current_source_line->file_line_number,current_source_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Renvoi la ligne */ + return(new_source_line); +} + +/***********************************************************************/ diff --git a/Source/a65816_Lup.h b/Source/a65816_Lup.h new file mode 100644 index 0000000..51dee5a --- /dev/null +++ b/Source/a65816_Lup.h @@ -0,0 +1,11 @@ +/***********************************************************************/ +/* */ +/* a65816_Lup.h : Header pour la gestion des Lup. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +int ReplaceLupWithCode(struct omf_segment *); + +/***********************************************************************/ diff --git a/Source/a65816_Macro.c b/Source/a65816_Macro.c new file mode 100644 index 0000000..4f09ed0 --- /dev/null +++ b/Source/a65816_Macro.c @@ -0,0 +1,962 @@ +/***********************************************************************/ +/* */ +/* a65816_Macro.c : Module pour la gestion des Macros . */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Dc_Library.h" +#include "a65816_File.h" +#include "a65816_Line.h" +#include "a65816_Macro.h" + +void LoadOneMacroFile(char *,char *,struct source_line *,struct omf_segment *); +static struct source_line *BuildMacroLine(struct source_line *,struct omf_segment *,struct omf_project *); +static struct source_line *BuildSourceMacroLine(struct source_line *,struct macro_line *,int,char **,struct omf_segment *); +static void BuildSubstituteValue(char *,int,char **,char *); +struct macro *mem_alloc_macro(char *,char *,int); +struct macro_line *mem_alloc_macroline(char *,char *,char *,char *); + +/******************************************************************/ +/* LoadAllMacroFile() : Chargement de tous les fichiers Macros. */ +/******************************************************************/ +void LoadAllMacroFile(char *folder_path, struct omf_segment *current_omfsegment) +{ + int i, nb_file, is_error; + char **tab_file_name; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /** Récupère les fichiers du répertoire **/ + tab_file_name = GetFolderFileList(folder_path,&nb_file,&is_error); + if(tab_file_name == NULL && is_error == 0) + return; + if(tab_file_name == NULL && is_error == 1) + { + printf(" => Error, Can't get files list from Macro folder '%s'.\n",folder_path); + return; + } + + /* Prépare le nom du dossier */ + strcpy(param->buffer_folder_path,folder_path); + if(strlen(param->buffer_folder_path) > 0) + if(param->buffer_folder_path[strlen(param->buffer_folder_path)-1] != '\\' && param->buffer_folder_path[strlen(param->buffer_folder_path)-1] != '/') + strcat(param->buffer_folder_path,FOLDER_SEPARATOR); + + /** On charge tous les fichiers .s présents **/ + for(i=0; ibuffer_folder_path,tab_file_name[i],NULL,current_omfsegment); + } + + /* Libération mémoire */ + mem_free_list(nb_file,tab_file_name); +} + + +/***********************************************************************/ +/* LoadSourceMacroFile() : Chargement des fichiers Macros du Source. */ +/***********************************************************************/ +void LoadSourceMacroFile(char *macro_folder_path, struct omf_segment *current_omfsegment) +{ + int i; + struct source_file *first_file; + struct source_line *current_line; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Récupère le Source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + + /*** Passe toutes les lignes en revue ***/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* Ligne déjà connue */ + if(current_line->type != LINE_UNKNOWN) + continue; + + /** On recherche les lignes USE **/ + if(!my_stricmp(current_line->opcode_txt,"USE") && strlen(current_line->operand_txt) > 0) + { + /* Ce fichier était peut être un fichier contenant du code */ + if(!IsMacroFile(current_line->operand_txt,param->source_folder_path,macro_folder_path)) + continue; + + /* On va extraire le nom du fichier : 4/Locator.Macs => Locator.Macs.s */ + for(i=(int)strlen(current_line->operand_txt); i>=0; i--) + if(current_line->operand_txt[i] == '/' || current_line->operand_txt[i] == ':') + break; + strcpy(param->buffer_file_name,¤t_line->operand_txt[i+1]); + + /* Ajoute le .s final */ + if(my_stricmp(¶m->buffer_file_name[strlen(param->buffer_file_name)-2],".s")) + strcat(param->buffer_file_name,".s"); + + /** Charge le fichier Macro **/ + printf(" - %s\n",param->buffer_file_name); + LoadOneMacroFile(macro_folder_path,param->buffer_file_name,current_line,current_omfsegment); + } + } +} + + +/*********************************************************/ +/* LoadOneMacroFile() : Chargement d'un fichier Macro. */ +/*********************************************************/ +void LoadOneMacroFile(char *folder_path, char *file_name, struct source_line *macro_line, struct omf_segment *current_omfsegment) +{ + int data_size, macro_level, line_number; + char *data; + char *begin_line; + char *end_line; + char *next_line; + struct macro *first_macro; + struct macro *last_macro; + struct macro *current_macro; + struct macro_line *current_line; + struct equivalence *current_equivalence; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + first_macro = NULL; + macro_level = 0; + + /* Chemin du fichier */ + sprintf((char *)param->buffer,"%s%s",folder_path,file_name); + + /* Chargement du fichier en mémoire (on recherche dans le dossier Library) */ + data = (char *) LoadTextFileData((char *)param->buffer,&data_size); + if(data == NULL) + { + /* On va regarder dans le dossier des sources */ + sprintf((char *)param->buffer,"%s%s",param->source_folder_path,file_name); + data = (char *) LoadTextFileData((char *)param->buffer,&data_size); + if(data == NULL) + { + if(macro_line != NULL) + sprintf(param->buffer_error,"Macro file '%s' not found (Source file '%s', line %d : use %s)",file_name,macro_line->file->file_name,macro_line->file_line_number,macro_line->operand_txt); + else + sprintf(param->buffer_error,"Impossible to load Macro file '%s'",param->buffer); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + } + my_Memory(MEMORY_DECLARE_ALLOC,data,NULL,current_omfsegment); + + /** Traite toutes les lignes du fichier **/ + line_number = 0; + begin_line = data; + while(begin_line) + { + /* Fin de la ligne */ + end_line = strchr(begin_line,'\n'); + if(end_line) + *end_line = '\0'; + next_line = (end_line == NULL) ? NULL : end_line + 1; + + /* Ligne vide */ + if(strlen(begin_line) == 0 || begin_line[0] == ';' || begin_line[0] == '*') + { + begin_line = next_line; + line_number++; + continue; + } + + /** On recherche les lignes MAC **/ + DecodeLine(begin_line,param->buffer_label,param->buffer_opcode,param->buffer_operand,param->buffer_comment); + if(!my_stricmp(param->buffer_opcode,"MAC")) + { + /* Macro Level */ + macro_level++; + + /* Nouvelle Macro */ + current_macro = mem_alloc_macro(file_name,param->buffer_label,line_number); + if(current_macro == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to register macro '%s' from file '%s'",param->buffer_label,file_name); + mem_free_macro_list(first_macro); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Attache la macro */ + if(first_macro == NULL) + first_macro = current_macro; + else + last_macro->next = current_macro; + last_macro = current_macro; + } + else if((!my_stricmp(param->buffer_opcode,"<<<") || !my_stricmp(param->buffer_opcode,"EOM")) && macro_level > 0) + { + /** Si cette ligne contient un Label, on l'intègre dans la macro comme ligne vide **/ + if(strlen(param->buffer_label) > 0) + { + for(current_macro=first_macro; current_macro; current_macro=current_macro->next) + { + /* Création de la ligne */ + current_line = mem_alloc_macroline(param->buffer_label,"","",param->buffer_comment); + if(current_line == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to process macro '%s' line '%s %s %s'",current_macro->name,param->buffer_label,param->buffer_opcode,param->buffer_operand); + mem_free_macro_list(first_macro); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Attachement */ + if(current_macro->first_line == NULL) + current_macro->first_line = current_line; + else + current_macro->last_line->next = current_line; + current_macro->last_line = current_line; + } + } + + /** On va terminer toutes les macros en cours **/ + for(current_macro=first_macro; current_macro; current_macro=current_macro->next) + my_Memory(MEMORY_ADD_MACRO,current_macro,NULL,current_omfsegment); + + /* Init */ + first_macro = NULL; + + /* Macro Level */ + macro_level = 0; + } + else if(macro_level > 0) + { + /** Ajoute cette macro_line aux macros enregistrées **/ + for(current_macro=first_macro; current_macro; current_macro=current_macro->next) + { + /* Création de la ligne */ + current_line = mem_alloc_macroline(param->buffer_label,param->buffer_opcode,param->buffer_operand,param->buffer_comment); + if(current_line == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to process macro '%s' line '%s %s %s'",current_macro->name,param->buffer_label,param->buffer_opcode,param->buffer_operand); + mem_free_macro_list(first_macro); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Attachement */ + if(current_macro->first_line == NULL) + current_macro->first_line = current_line; + else + current_macro->last_line->next = current_line; + current_macro->last_line = current_line; + } + } + else + { + /** On est à l'extérieur de la définition d'une Macro, il peut y avoir des EQU qui trainent (Util.Macs.s) **/ + if((!my_stricmp(param->buffer_opcode,"=") || !my_stricmp(param->buffer_opcode,"EQU")) && strlen(param->buffer_label) > 0) + { + /** Allocation de la structure Equivalence **/ + current_equivalence = (struct equivalence *) calloc(1,sizeof(struct equivalence)); + if(current_equivalence == NULL) + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for structure equivalence"); + current_equivalence->name = strdup(param->buffer_label); + current_equivalence->value = strdup(param->buffer_operand); + if(current_equivalence->name == NULL || current_equivalence->value == NULL) + { + mem_free_equivalence(current_equivalence); + my_RaiseError(ERROR_RAISE,"Impossible to allocate memory for 'name' from structure equivalence"); + } + + /* Déclaration de la structure */ + my_Memory(MEMORY_ADD_EQUIVALENCE,current_equivalence,NULL,current_omfsegment); + } + } + + /* Ligne suivante */ + begin_line = next_line; + line_number++; + } + + /* Libération mémoire */ + my_Memory(MEMORY_FREE_ALLOC,data,NULL,current_omfsegment); +} + + +/*********************************************************************/ +/* GetMacroFromSource() : Récupère les macros des fichiers Source. */ +/*********************************************************************/ +void GetMacroFromSource(struct omf_segment *current_omfsegment) +{ + struct macro *first_macro; + struct macro *last_macro; + struct macro *current_macro; + struct source_file *first_file; + struct source_line *current_line; + struct macro_line *current_macroline; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + first_macro = NULL; + + /* Récupère le 1er fichier source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + if(first_file == NULL) + return; + + /*** Passe en revue toutes les lignes ***/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + if(!my_stricmp(current_line->opcode_txt,"MAC")) + { + /* Nouvelle Macro */ + current_macro = mem_alloc_macro(current_line->file->file_name,current_line->label_txt,current_line->file_line_number); + if(current_macro == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to register macro '%s' from file '%s'",current_line->label_txt,current_line->file->file_name); + mem_free_macro_list(first_macro); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Attache la macro */ + if(first_macro == NULL) + first_macro = current_macro; + else + last_macro->next = current_macro; + last_macro = current_macro; + + /* Cette ligne est de type définition de macro */ + current_line->type = LINE_DIRECTIVE; + current_line->type_aux = LINE_MACRO_DEF; + + /* Il s'agit d'une Macro déclarée dans le Source */ + current_line->is_inside_macro = 1; + } + else if(!my_stricmp(current_line->opcode_txt,"<<<") || !my_stricmp(current_line->opcode_txt,"EOM")) + { + /** Si cette ligne contient un Label, on l'intègre dans la macro comme ligne vide **/ + if(strlen(current_line->label_txt) > 0) + { + for(current_macro=first_macro; current_macro; current_macro=current_macro->next) + { + /* Création de la ligne */ + current_macroline = mem_alloc_macroline(current_line->label_txt,"","",current_line->comment_txt); + if(current_macroline == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to process macro '%s' line '%s %s %s'",current_macro->name,current_line->label_txt,current_line->opcode_txt,current_line->operand_txt); + mem_free_macro_list(first_macro); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Attachement */ + if(current_macro->first_line == NULL) + current_macro->first_line = current_macroline; + else + current_macro->last_line->next = current_macroline; + current_macro->last_line = current_macroline; + } + } + + /** On va terminer toutes les macros en cours **/ + for(current_macro=first_macro; current_macro; current_macro=current_macro->next) + my_Memory(MEMORY_ADD_MACRO,current_macro,NULL,current_omfsegment); + + /* Init */ + first_macro = NULL; + + /* Cette ligne est de type définition de macro */ + current_line->type = LINE_DIRECTIVE; + current_line->type_aux = LINE_MACRO_DEF; + + /* Il s'agit d'une Macro déclarée dans le Source */ + current_line->is_inside_macro = 1; + } + else if(first_macro != NULL) + { + /** Ajoute cette macro_line aux macros enregistrées **/ + for(current_macro=first_macro; current_macro; current_macro=current_macro->next) + { + /* Création de la ligne */ + current_macroline = mem_alloc_macroline(current_line->label_txt,current_line->opcode_txt,current_line->operand_txt,current_line->comment_txt); + if(current_line == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to process macro '%s' line '%s %s %s'",current_macro->name,current_line->label_txt,current_line->opcode_txt,current_line->operand_txt); + mem_free_macro_list(first_macro); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Attachement */ + if(current_macro->first_line == NULL) + current_macro->first_line = current_macroline; + else + current_macro->last_line->next = current_macroline; + current_macro->last_line = current_macroline; + } + + /* Cette ligne est de type définition de macro */ + current_line->type = LINE_DIRECTIVE; + current_line->type_aux = LINE_MACRO_DEF; + + /* Il s'agit d'une Macro déclarée dans le Source */ + current_line->is_inside_macro = 1; + } + } +} + + +/***********************************************************************/ +/* CheckForDuplicatedMacro() : Recherche de Macro ayant le même nom. */ +/***********************************************************************/ +void CheckForDuplicatedMacro(struct omf_segment *current_omfsegment) +{ + int i, nb_macro; + struct macro *previous_macro = NULL; + struct macro *current_macro; + + /** Passe en revue toutes les Macro **/ + my_Memory(MEMORY_GET_MACRO_NB,&nb_macro,NULL,current_omfsegment); + for(i=1; i<=nb_macro; i++) + { + my_Memory(MEMORY_GET_MACRO,&i,¤t_macro,current_omfsegment); + if(current_macro != NULL && previous_macro != NULL) + if(!strcmp(current_macro->name,previous_macro->name)) + printf(" [Warning] Macro : '%s' found in '%s' and '%s'\n",current_macro->name,previous_macro->file_name,current_macro->file_name); + + previous_macro = current_macro; + } +} + + +/********************************************************************/ +/* ReplaceMacroWithContent() : Remplace les Macros par leur code. */ +/********************************************************************/ +int ReplaceMacroWithContent(struct omf_segment *current_omfsegment, struct omf_project *current_omfproject) +{ + struct source_file *first_file; + struct source_line *current_line; + struct source_line *first_macro_line; + struct source_line *last_macro_line; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Récupère le 1er fichier source */ + my_Memory(MEMORY_GET_FILE,&first_file,NULL,current_omfsegment); + if(first_file == NULL) + return(0); + + /*** Passe en revue toutes les lignes ***/ + for(current_line=first_file->first_line; current_line; current_line=current_line->next) + { + /* On ignore les lignes invalides */ + if(current_line->is_valid == 0) + continue; + + /** Recherche les appels de Macro **/ + if(current_line->type == LINE_MACRO) + { + /* Construit les lignes de codes de cette Macro en y intégrant les paramètres et en remplaçant les Labels */ + first_macro_line = BuildMacroLine(current_line,current_omfsegment,current_omfproject); + if(first_macro_line == NULL) + { + /* Erreur */ + return(1); + } + /* Dernière ligne de la Macro */ + for(last_macro_line = first_macro_line; last_macro_line->next != NULL; last_macro_line=last_macro_line->next) + ; + + /** Insère les lignes de Code derrière l'appel de la Macro **/ + last_macro_line->next = current_line->next; + current_line->next = first_macro_line; + + /* Ligne suivante */ + current_line = last_macro_line; + } + } + + /* OK */ + return(0); +} + + +/************************************************************************/ +/* BuildMacroLine() : Création des lignes de code venant d'une Macro. */ +/************************************************************************/ +static struct source_line *BuildMacroLine(struct source_line *current_source_line, struct omf_segment *current_omfsegment, struct omf_project *current_omfproject) +{ + struct macro *current_macro; + struct source_line *new_source_line = NULL; + struct source_line *label_source_line = NULL; + struct source_line *first_source_line = NULL; + struct source_line *last_source_line = NULL; + struct source_line *first_source_macro_line; + struct source_line *last_source_macro_line; + struct macro_line *current_macro_line = NULL; + char *next_sep; + char *new_operand; + char *var_list = NULL; + int i, j, nb_error, nb_var = 0; + char **var_tab; + char label_unique[256]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + current_macro = current_source_line->macro; + + /****************************************/ + /** Extrait les variables de l'appel **/ + /****************************************/ + /* Init */ + var_tab = (char **) calloc(9,sizeof(char *)); + if(var_tab == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to replace macro '%s' at line %d from file '%s' [Build Line]",current_macro->name,current_source_line->file_line_number,current_source_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + for(i=0; i<9; i++) + { + var_tab[i] = (char *) calloc(256,sizeof(char)); + if(var_tab[i] == NULL) + { + for(j=0; jbuffer_error,"Impossible to allocate memory to replace macro '%s' at line %d from file '%s' [Build Line]",current_macro->name,current_source_line->file_line_number,current_source_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + } + + /** On se positionne au début des paramètres **/ + if(!my_stricmp(current_source_line->opcode_txt,"PMC") || !my_stricmp(current_source_line->opcode_txt,">>>")) + { + /* Le nom de la Macro et les paramètres sont collés dans l'Operande */ + for(i=0; i<(int)strlen(current_source_line->operand_txt); i++) + if(current_source_line->operand_txt[i] == '.' || current_source_line->operand_txt[i] == '/' || current_source_line->operand_txt[i] == ',' || + current_source_line->operand_txt[i] == '-' || current_source_line->operand_txt[i] == '(' || current_source_line->operand_txt[i] == ' ') + { + var_list = ¤t_source_line->operand_txt[i+1]; + break; + } + } + else + var_list = strlen(current_source_line->operand_txt) == 0 ? NULL : current_source_line->operand_txt; + + /** Il n'y a que 8 variables maximum séparées par des ; **/ + while(var_list) + { + next_sep = strchr(var_list,';'); + + /* Dernière entrées */ + if(next_sep == NULL) + { + strcpy(var_tab[nb_var+1],var_list); + nb_var++; + break; + } + + /* Copie l'entrée */ + memcpy(var_tab[nb_var+1],var_list,next_sep-var_list); + var_tab[nb_var+1][next_sep-var_list] = '\0'; + nb_var++; + + /* On avance */ + var_list += (next_sep-var_list+1); + } + sprintf(var_tab[0],"%d",nb_var); + + /*** Duplication des lignes de la Macro ***/ + for(current_macro_line=current_macro->first_line; current_macro_line; current_macro_line=current_macro_line->next) + { + /* Création de la ligne Source */ + new_source_line = BuildSourceMacroLine(current_source_line,current_macro_line,nb_var,var_tab,current_omfsegment); + if(new_source_line == NULL) + { + for(i=0; i<9; i++) + free(var_tab[i]); + free(var_tab); + sprintf(param->buffer_error,"Impossible to allocate memory to replace macro '%s' at line %d from file '%s' [Build Line]",current_macro->name,current_source_line->file_line_number,current_source_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + + /* Attachement de la ligne Source */ + if(first_source_line == NULL) + first_source_line = new_source_line; + else + last_source_line->next = new_source_line; + last_source_line = new_source_line; + } + + /* Libération mémoire */ + for(i=0; i<9; i++) + free(var_tab[i]); + free(var_tab); + + /*** On va modifier les Labels Globaux pour obtenir qqchose d'unique ***/ + for(new_source_line=first_source_line; new_source_line; new_source_line=new_source_line->next) + { + /* On ne va traiter que les Labels globaux */ + if(strlen(new_source_line->label_txt) > 0 && new_source_line->label_txt[0] != ':' && new_source_line->label_txt[0] != ']') + { + /* Création d'un label unique */ + GetUNID(&label_unique[0]); + + /** On passe toutes les lignes en revue **/ + for(label_source_line=first_source_line; label_source_line; label_source_line=label_source_line->next) + { + /** Remplace le Label dans l'Operand **/ + new_operand = ReplaceInOperand(label_source_line->operand_txt,new_source_line->label_txt,label_unique,SEPARATOR_REPLACE_VARIABLE,label_source_line); + if(new_operand != label_source_line->operand_txt) + { + free(label_source_line->operand_txt); + label_source_line->operand_txt = new_operand; + } + } + + /* On le remplace dans la ligne l'ayant définie */ + free(new_source_line->label_txt); + new_source_line->label_txt = strdup(label_unique); + if(new_source_line->label_txt == NULL) + { + sprintf(param->buffer_error,"Impossible to allocate memory to replace macro '%s' at line %d from file '%s' [Update Label]",current_macro->name,current_source_line->file_line_number,current_source_line->file->file_name); + my_RaiseError(ERROR_RAISE,param->buffer_error); + } + } + } + + /** On va analyser les nouvelles lignes pour déterminer leurs Types **/ + nb_error = DecodeLineType(first_source_line,current_macro,current_omfsegment,current_omfproject); + if(nb_error > 0) + { + /* Erreur : On efface tout et on sort en erreur */ + mem_free_sourceline_list(first_source_line); + return(NULL); + } + + /** On a détecté une macro => Il faut substituer cet appel avec les lignes de code (récursivité) **/ + for(new_source_line=first_source_line; new_source_line; new_source_line=new_source_line->next) + { + if(new_source_line->type == LINE_MACRO) + { + /** Création des lignes substituées **/ + first_source_macro_line = BuildMacroLine(new_source_line,current_omfsegment,current_omfproject); + if(first_source_macro_line == NULL) + { + /* Erreur : On efface tout et on sort en erreur */ + mem_free_sourceline_list(first_source_line); + return(NULL); + } + /* On se positionne à la fin */ + for(last_source_macro_line=first_source_macro_line; last_source_macro_line->next != NULL; last_source_macro_line = last_source_macro_line->next) + ; + + /** Insère les lignes substituées à leur place **/ + last_source_macro_line->next = new_source_line->next; + new_source_line->next = first_source_macro_line; + + /* Ligne suivante */ + new_source_line = last_source_macro_line; + } + } + + /* Renvoi les lignes */ + return(first_source_line); +} + + +/****************************************************************************************/ +/* BuildSourceMacroLine() : Construction d'une ligne de Source provenant d'une Macro. */ +/****************************************************************************************/ +static struct source_line *BuildSourceMacroLine(struct source_line *current_source_line, struct macro_line *current_macro_line, int nb_var, char **var_tab, struct omf_segment *current_omfsegment) +{ + int is_modified; + struct source_line *new_source_line = NULL; + char buffer[1024]; + + /* Allocation de la nouvelle ligne */ + new_source_line = (struct source_line *) calloc(1,sizeof(struct source_line)); + if(new_source_line == NULL) + return(NULL); + + /** Transfert les caractéristiques de la ligne Source (numéro de la ligne...) **/ + new_source_line->file_line_number = current_source_line->file_line_number; + new_source_line->file = current_source_line->file; + new_source_line->type = LINE_UNKNOWN; + new_source_line->address = -1; + new_source_line->nb_byte = -1; + new_source_line->is_valid = 1; /* la ligne est valide */ + new_source_line->operand_value = 0xFFFFFFFF; + new_source_line->operand_address_long = 0xFFFFFFFF; + strcpy(new_source_line->m,"?"); + strcpy(new_source_line->x,"?"); + strcpy(new_source_line->reloc," "); + + /** Transfert les éléments de la ligne Macro **/ + BuildSubstituteValue(current_macro_line->label,nb_var,var_tab,buffer); + new_source_line->label_txt = strdup(buffer); + BuildSubstituteValue(current_macro_line->opcode,nb_var,var_tab,buffer); + new_source_line->opcode_txt = strdup(buffer); + BuildSubstituteValue(current_macro_line->operand,nb_var,var_tab,buffer); + new_source_line->operand_txt = strdup(buffer); + BuildSubstituteValue(current_macro_line->comment,nb_var,var_tab,buffer); + new_source_line->comment_txt = strdup(buffer); + if(new_source_line->label_txt == NULL || new_source_line->opcode_txt == NULL || new_source_line->operand_txt == NULL || new_source_line->comment_txt == NULL) + { + mem_free_sourceline(new_source_line); + return(NULL); + } + + /* Remplace les Equivalences sur la Ligne */ + is_modified = ProcessLineEquivalence(new_source_line,current_omfsegment); + + /* Renvoi la ligne */ + return(new_source_line); +} + + +/***************************************************************************************/ +/* BuildSubstituteValue() : On remplace les ]x par les valeurs passées en paramètre. */ +/***************************************************************************************/ +static void BuildSubstituteValue(char *src_string, int nb_var, char **var_tab, char *dst_string_rtn) +{ + int i, j; + + /* On recherche un ] */ + for(i=0,j=0; i<(int)strlen(src_string); i++) + if(src_string[i] == ']' && (src_string[i+1] >= '0' && src_string[i+1] <= '8')) + { + memcpy(&dst_string_rtn[j],var_tab[src_string[i+1]-'0'],strlen(var_tab[src_string[i+1]-'0'])); + j += (int) strlen(var_tab[src_string[i+1]-'0']); + i++; + } + else + dst_string_rtn[j++] = src_string[i]; + + /* Fin de chaine */ + dst_string_rtn[j] = '\0'; +} + + +/******************************************************************/ +/* IsMacroFile() : Détermine si ce fichier contient des Macros. */ +/******************************************************************/ +int IsMacroFile(char *file_name, char *source_folder_path, char *macro_folder_path) +{ + int i, found; + struct source_file *macro_file; + struct source_line *current_line; + char file_path[1024]; + struct parameter *param; + my_Memory(MEMORY_GET_PARAM,¶m,NULL,NULL); + + /* Init */ + found = 0; + + /* On va vite, on regarde le nom */ + if(strlen(file_name) > strlen(".Macs.s")) + if(!my_stricmp(&file_name[strlen(file_name)-strlen(".Macs.s")],".Macs.s")) + return(1); + if(strlen(file_name) > strlen(".Macs")) + if(!my_stricmp(&file_name[strlen(file_name)-strlen(".Macs")],".Macs")) + return(1); + + /* On essaye d'ouvrir le fichier avec son nom */ + sprintf(file_path,"%s%s",source_folder_path,file_name); + macro_file = LoadOneSourceFile(file_path,file_name,0); + if(macro_file == NULL) + { + /** On ajoute un .S à la fin **/ + strcat(file_path,".s"); + macro_file = LoadOneSourceFile(file_path,file_name,0); + + /** On va nettoyer le nom du fichier **/ + if(macro_file == NULL) + { + /* On va extraire le nom du fichier : 4/Locator.Macs => Locator.Macs.s */ + for(i=(int)strlen(file_name); i>=0; i--) + if(file_name[i] == '/' || file_name[i] == ':') + break; + strcpy(param->buffer_file_name,&file_name[i+1]); + + /* Ajoute le .s final */ + if(my_stricmp(¶m->buffer_file_name[strlen(param->buffer_file_name)-2],".s")) + strcat(param->buffer_file_name,".s"); + + /* On essaye d'ouvrir le fichier avec son nom */ + sprintf(file_path,"%s%s",macro_folder_path,param->buffer_file_name); + macro_file = LoadOneSourceFile(file_path,param->buffer_file_name,0); + } + } + + /* On a pas réussi à ouvrir le fichier, on le déclare comme un fichier Macro et on laisse le code suivant le déclarer non disponble */ + if(macro_file == NULL) + return(1); + + /** On va analyser les lignes afin de trouver du MAC >>> **/ + /* Fichier vide ? */ + if(macro_file->first_line == NULL) + { + mem_free_sourcefile(macro_file,1); + return(1); + } + + /** On passe toutes les lignes en revue **/ + for(current_line = macro_file->first_line; current_line; current_line = current_line->next) + { + /* Commentaire / Vide */ + if(current_line->type == LINE_COMMENT || current_line->type == LINE_EMPTY) + continue; + + /* Reconnait les Opcode des Macro */ + if(!my_stricmp(current_line->opcode_txt,"MAC")) + { + found = 1; + break; + } + } + + /* Libération mémoire */ + mem_free_sourcefile(macro_file,1); + + /* Indique si on a trouvé des Macro */ + return(found); +} + + +/*******************************************************************/ +/* mem_alloc_macro() : Allocation mémoire de la structure macro. */ +/*******************************************************************/ +struct macro *mem_alloc_macro(char *file_name, char *name, int line_number) +{ + struct macro *current_macro; + + /* Allocation mémoire */ + current_macro = (struct macro *) calloc(1,sizeof(struct macro)); + if(current_macro == NULL) + return(NULL); + + /* Remplissage */ + current_macro->file_line_number = line_number; + current_macro->file_name = strdup(file_name); + current_macro->name = strdup(name); + if(current_macro->file_name == NULL || current_macro->name == NULL) + { + mem_free_macro(current_macro); + return(NULL); + } + + /* Retourne la structure */ + return(current_macro); +} + + +/****************************************************************************/ +/* mem_alloc_macroline() : Allocation mémoire de la structure macro_line. */ +/****************************************************************************/ +struct macro_line *mem_alloc_macroline(char *label, char *opcode, char *operand, char *comment) +{ + struct macro_line *current_line; + + /* Allocation mémoire */ + current_line = (struct macro_line *) calloc(1,sizeof(struct macro_line)); + if(current_line == NULL) + return(NULL); + + /* Remplissage */ + current_line->label = strdup(label); + current_line->opcode = strdup(opcode); + current_line->operand = strdup(operand); + current_line->comment = strdup(comment); + if(current_line->label == NULL || current_line->opcode == NULL || current_line->operand == NULL || current_line->comment == NULL) + { + mem_free_macroline(current_line); + return(NULL); + } + + /* Retourne la structure */ + return(current_line); +} + + +/***************************************************************************/ +/* mem_free_macroline() : Libération mémoire de la structure macro_line. */ +/***************************************************************************/ +void mem_free_macroline(struct macro_line *current_line) +{ + if(current_line) + { + if(current_line->label) + free(current_line->label); + + if(current_line->opcode) + free(current_line->opcode); + + if(current_line->operand) + free(current_line->operand); + + if(current_line->comment) + free(current_line->comment); + + free(current_line); + } +} + + +/******************************************************************/ +/* mem_free_macro() : Libération mémoire de la structure macro. */ +/******************************************************************/ +void mem_free_macro(struct macro *current_macro) +{ + struct macro_line *current_line; + struct macro_line *next_line; + + if(current_macro) + { + if(current_macro->name) + free(current_macro->name); + + if(current_macro->file_name) + free(current_macro->file_name); + + for(current_line=current_macro->first_line; current_line; ) + { + next_line = current_line->next; + mem_free_macroline(current_line); + current_line = next_line; + } + + free(current_macro); + } +} + + +/**********************************************************************/ +/* mem_free_macro_list() : Libération mémoire des structures macro. */ +/**********************************************************************/ +void mem_free_macro_list(struct macro *all_macro) +{ + struct macro *current_macro; + struct macro *next_macro; + + for(current_macro=all_macro; current_macro; ) + { + next_macro = current_macro->next; + mem_free_macro(current_macro); + current_macro = next_macro; + } +} + +/***********************************************************************/ diff --git a/Source/a65816_Macro.h b/Source/a65816_Macro.h new file mode 100644 index 0000000..712b103 --- /dev/null +++ b/Source/a65816_Macro.h @@ -0,0 +1,42 @@ +/***********************************************************************/ +/* */ +/* a65816_Macro.h : Module pour la gestion des Macros . */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +struct macro +{ + char *name; + + char *file_name; /* Nom du fichier Macro contenant cette Macro */ + int file_line_number; /* Numéro de ligne du fichier Macro où commence cette Macro */ + + struct macro_line *first_line; + struct macro_line *last_line; + + struct macro *next; +}; + +struct macro_line +{ + char *label; + char *opcode; + char *operand; + char *comment; + + struct macro_line *next; +}; + +void LoadAllMacroFile(char *,struct omf_segment *); +void LoadSourceMacroFile(char *,struct omf_segment *); +void GetMacroFromSource(struct omf_segment *); +void CheckForDuplicatedMacro(struct omf_segment *); +int ReplaceMacroWithContent(struct omf_segment *,struct omf_project *); +int IsMacroFile(char *,char *,char *); +void mem_free_macro(struct macro *); +void mem_free_macro_list(struct macro *); +void mem_free_macroline(struct macro_line *); + +/***********************************************************************/ diff --git a/Source/a65816_OMF.c b/Source/a65816_OMF.c new file mode 100644 index 0000000..04cbf83 --- /dev/null +++ b/Source/a65816_OMF.c @@ -0,0 +1,1597 @@ +/***********************************************************************/ +/* */ +/* a65816_OMF.c : Module pour la gestion du fichier OMF. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "Dc_Library.h" +#include "a65816_Line.h" +#include "a65816_File.h" +#include "a65816_Lup.h" +#include "a65816_Macro.h" +#include "a65816_Cond.h" +#include "a65816_Code.h" +#include "a65816_Data.h" +#include "a65816_OMF.h" + +static void mem_init_omfsegment(struct omf_segment *); + +/*********************************************************/ +/* BuildOMFFile() : Création du fichier au format OMF. */ +/*********************************************************/ +int BuildOMFFile(char *output_folder_path, struct omf_project *current_omfproject) +{ + FILE *fd; + int offset, nb_write; + char *file_name; + char file_path[1024]; + struct omf_segment *current_omfsegment; + + /*************************************/ + /*** Création du fichier Project ***/ + /*************************************/ + /* Taille du fichier Project (on prend large) */ + current_omfproject->project_buffer_length = 1024; + for(current_omfsegment=current_omfproject->first_segment; current_omfsegment; current_omfsegment=current_omfsegment->next) + current_omfproject->project_buffer_length += (current_omfsegment->header_length + current_omfsegment->body_length); + + /** Allocation mémoire Project (on prend plus large) **/ + current_omfproject->project_buffer_file = (unsigned char *) calloc(current_omfproject->project_buffer_length,sizeof(unsigned char)); + if(current_omfproject->project_buffer_file == NULL) + { + printf(" Error : Can't allocate memory to build OMF File buffer.\n"); + return(1); + } + + /** Ajout des Data (Header+Body) des Segments **/ + for(offset=0,current_omfsegment=current_omfproject->first_segment; current_omfsegment; current_omfsegment=current_omfsegment->next) + { + /* Header */ + memcpy(¤t_omfproject->project_buffer_file[offset],current_omfsegment->segment_header_file,current_omfsegment->header_length); + offset += current_omfsegment->header_length; + + /* Body */ + memcpy(¤t_omfproject->project_buffer_file[offset],current_omfsegment->segment_body_file,current_omfsegment->body_length); + offset += current_omfsegment->body_length; + } + current_omfproject->project_file_length = offset; + + /*******************************************/ + /*** Création du fichier sur le disque ***/ + /*******************************************/ + /* Nom du fichier */ + if(current_omfproject->dsk_name_tab == NULL) + file_name = current_omfproject->first_segment->object_name; /* Mono Segment */ + else + file_name = current_omfproject->dsk_name_tab[0]; + + /* Chemin du fichier */ + sprintf(file_path,"%s%s",output_folder_path,file_name); + + /* Information */ + printf(" => Creating OMF file '%s'\n",file_path); + + /* Création du fichier */ +#if defined(WIN32) || defined(WIN64) + fd = fopen(file_path,"wb+"); +#else + fd = fopen(file_path,"w+"); +#endif + if(fd == NULL) + { + printf(" Error : Can't create OMF file '%s'.\n",file_path); + return(1); + } + + /* Ecriture des structures OMF dans le fichier */ + nb_write = (int) fwrite(current_omfproject->project_buffer_file,1,current_omfproject->project_file_length,fd); + if(nb_write != current_omfproject->project_file_length) + printf(" Error : Can't write OMF file '%s' data (%d bytes / %d bytes).\n",file_path,nb_write,(int)current_omfproject->project_file_length); + + /* Fermeture du fichier */ + fclose(fd); + + /*** Mise à jour du fichier _FileInformation.txt ***/ + UpdateFileInformation(output_folder_path,file_name,current_omfproject); + + /* OK */ + return(0); +} + + +/************************************************/ +/* BuildOMFBody() : Construction du Body OMF. */ +/************************************************/ +DWORD BuildOMFBody(struct omf_project *current_omfproject, struct omf_segment *current_omfsegment) +{ + DWORD offset, offset_length, offset_data, length; + BYTE one_byte, current_page, address_page; + WORD one_word; + DWORD one_dword; + DWORD address_patch; + BYTE address_path_byte[4]; + unsigned char *buffer_body; + int i, nb_address, nb_creloc, nb_super_creloc2, nb_super_creloc3, nb_cinterseg, nb_super_interseg1; + int nb_super_interseg_13_24[12]; + int nb_super_interseg_25_36[12]; + struct relocate_address *current_address; + struct relocate_address *next_address; + + /* Init */ + offset = 0; + buffer_body = current_omfsegment->segment_body_file; + + /****************/ + /*** LCONST ***/ + /****************/ + /* Record Type */ + one_byte = 0xF2; + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* Number of byte */ + one_dword = current_omfsegment->object_length; + bo_memcpy(&buffer_body[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + + /* Conserve l'offset des Data pour l'ExpressLoad */ + current_omfsegment->xpress_data_offset = offset; + + /* Data */ + offset_data = offset; + memcpy(&buffer_body[offset],current_omfsegment->object_code,current_omfsegment->object_length); + offset += current_omfsegment->object_length; + + /* Conserve la longueur des Data pour l'ExpressLoad */ + current_omfsegment->xpress_data_length = current_omfsegment->object_length; + + /********************************************/ + /** Stat sur les Types d'adresse à reloger **/ + /********************************************/ + nb_address = 0; + nb_super_creloc2 = 0; + nb_super_creloc3 = 0; + nb_creloc = 0; + nb_cinterseg = 0; + nb_super_interseg1 = 0; + for(i=0; i<12; i++) + { + nb_super_interseg_13_24[i] = 0; + nb_super_interseg_25_36[i] = 0; + } + for(current_address = current_omfsegment->first_address; current_address; current_address=current_address->next) + { + /* Nombre total d'adresses */ + nb_address++; + + /* Internes */ + if(current_address->external == NULL) + { + if(current_address->ByteCnt == 2 && current_address->BitShiftCnt == 0x00) + nb_super_creloc2++; + else if(current_address->ByteCnt == 3 && current_address->BitShiftCnt == 0x00) + nb_super_creloc3++; + else + nb_creloc++; /* TO DO : pour les segement Data > 64 KB, prévoir des RELOC */ + } + else /* Externes */ + { + if(current_address->ByteCnt == 3 && current_address->BitShiftCnt == 0x00) + nb_super_interseg1++; + else if(current_address->external->external_segment->segment_number <= 12 && current_address->ByteCnt == 2 && current_address->BitShiftCnt == 0x00) + nb_super_interseg_13_24[current_address->external->external_segment->segment_number-1] += 1; + else if(current_address->external->external_segment->segment_number <= 12 && current_address->ByteCnt == 2 && current_address->BitShiftCnt == 0xF0) /* -16 */ + nb_super_interseg_25_36[current_address->external->external_segment->segment_number-1] += 1; + else + nb_cinterseg++; /* To Do : Pour les Segments Data > 64 KB ou si le nb de Segment > 256, utiliser les INTERSEG */ + } + } + + /*****************************************************************/ + /*** SUPER, CRELOC2 : Adresses Internes, 2 Bytes, pas de Shift ***/ + /*****************************************************************/ + if(nb_super_creloc2 > 0) + { + /* Conserve l'offset des Reloc pour l'ExpressLoad */ + if(current_omfsegment->xpress_reloc_offset == 0) + current_omfsegment->xpress_reloc_offset = offset; + + /* Record Type */ + one_byte = 0xF7; /* SUPER : Super Compress Relocation Dictionary */ + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* Length */ + offset_length = offset; + length = 0; + offset += sizeof(DWORD); + /* Type */ + one_byte = 0x00; /* Super Reloc2 */ + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + + /* Conserve la longueur des Reloc pour l'ExpressLoad */ + current_omfsegment->xpress_reloc_length += (sizeof(BYTE) + sizeof(DWORD) + sizeof(BYTE)); + + /** On va y placer toutes les adresses par Page **/ + current_page = 0x00; + for(nb_address = 0,current_address = current_omfsegment->first_address; current_address; current_address=current_address->next) + if(current_address->processed == 0 && current_address->external == NULL && current_address->ByteCnt == 2 && current_address->BitShiftCnt == 0x00) + { + /* Page de cette addresse */ + address_page = (BYTE) (current_address->OffsetPatch >> 8); + + /* Doit t'on sauter des Pages ? */ + if(address_page != current_page) + { + /* Skip # Pages */ + if(address_page - current_page <= 0x7F) + { + /* 1 seul Byte de Skip Page suffit */ + one_byte = 0x80 | (address_page - current_page); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + } + else + { + /* il faut 2 Bytes de Skip Page */ + one_byte = 0xFF; + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + + one_byte = 0x80 | (address_page - current_page - 0x7F); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + } + + current_page = address_page; + } + + /** On détermine le nombre d'adresse sur cette Page **/ + for(nb_address = 1,next_address = current_address->next; next_address; next_address=next_address->next) + if(next_address->processed == 0 && next_address->external == NULL && next_address->ByteCnt == 2 && next_address->BitShiftCnt == 0x00) + { + if((BYTE) (next_address->OffsetPatch >> 8) == address_page) + nb_address++; + else + break; + } + + /* Nombre d'adresse */ + one_byte = (BYTE) (nb_address-1); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + + /** Liste des addresses de cette Page **/ + for(next_address = current_address; next_address; next_address=next_address->next) + if(next_address->processed == 0 && next_address->external == NULL && next_address->ByteCnt == 2 && next_address->BitShiftCnt == 0x00) + { + if((BYTE) (next_address->OffsetPatch >> 8) == address_page) + { + /* Partie basse de l'adresse */ + one_byte = (BYTE) (0x00FF & next_address->OffsetPatch); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + + /* Cette addresse est traitée */ + next_address->processed = 1; + } + else + break; + } + + /* Page suivante */ + current_page++; + } + + /* Conserve la longueur des Reloc pour l'ExpressLoad */ + current_omfsegment->xpress_reloc_length += length; + + /** Longueur du Super **/ + length += sizeof(BYTE); /* Type */ + bo_memcpy(&buffer_body[offset_length],&length,sizeof(DWORD)); + } + + /*****************************************************************/ + /*** SUPER, CRELOC3 : Adresses Internes, 3 Bytes, pas de Shift ***/ + /*****************************************************************/ + if(nb_super_creloc3 > 0) + { + /* Conserve l'offset des Reloc pour l'ExpressLoad */ + if(current_omfsegment->xpress_reloc_offset == 0) + current_omfsegment->xpress_reloc_offset = offset; + + /* Record Type */ + one_byte = 0xF7; /* SUPER : Super Compress Relocation Dictionary */ + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* Length */ + offset_length = offset; + length = 0; + offset += sizeof(DWORD); + /* Type */ + one_byte = 0x01; /* Super Reloc3 */ + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + + /* Conserve la longueur des Reloc pour l'ExpressLoad */ + current_omfsegment->xpress_reloc_length += (sizeof(BYTE) + sizeof(DWORD) + sizeof(BYTE)); + + /** On va y placer toutes les adresses par Page **/ + current_page = 0x00; + for(nb_address = 0,current_address = current_omfsegment->first_address; current_address; current_address=current_address->next) + if(current_address->processed == 0 && current_address->external == NULL && current_address->ByteCnt == 3 && current_address->BitShiftCnt == 0x00) + { + /* Page de cette addresse */ + address_page = (BYTE) (current_address->OffsetPatch >> 8); + + /* Doit t'on sauter des Pages ? */ + if(address_page != current_page) + { + /* Skip # Pages */ + if(address_page - current_page <= 0x7F) + { + /* 1 seul Byte de Skip Page suffit */ + one_byte = 0x80 | (address_page - current_page); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + } + else + { + /* il faut 2 Bytes de Skip Page */ + one_byte = 0xFF; + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + + one_byte = 0x80 | (address_page - current_page - 0x7F); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + } + + current_page = address_page; + } + + /** On détermine le nombre d'adresse sur cette Page **/ + for(nb_address = 1,next_address = current_address->next; next_address; next_address=next_address->next) + if(next_address->processed == 0 && next_address->external == NULL && next_address->ByteCnt == 3 && next_address->BitShiftCnt == 0x00) + { + if((BYTE) (next_address->OffsetPatch >> 8) == address_page) + nb_address++; + else + break; + } + + /* Nombre d'adresse */ + one_byte = (BYTE) (nb_address-1); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + + /** Liste des addresses de cette Page **/ + for(next_address = current_address; next_address; next_address=next_address->next) + if(next_address->processed == 0 && next_address->external == NULL && next_address->ByteCnt == 3 && next_address->BitShiftCnt == 0x00) + { + if((BYTE) (next_address->OffsetPatch >> 8) == address_page) + { + /* Partie basse de l'adresse */ + one_byte = (BYTE) (0x00FF & next_address->OffsetPatch); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + + /* Cette addresse est traitée */ + next_address->processed = 1; + } + else + break; + } + + /* Page suivante */ + current_page++; + } + + /* Conserve la longueur des Reloc pour l'ExpressLoad */ + current_omfsegment->xpress_reloc_length += length; + + /** Longueur du Super **/ + length += sizeof(BYTE); /* Type */ + bo_memcpy(&buffer_body[offset_length],&length,sizeof(DWORD)); + } + + /**********************************/ + /*** cRELOC : Adresses Internes ***/ + /**********************************/ + if(nb_creloc > 0) + { + for(current_address = current_omfsegment->first_address; current_address; current_address=current_address->next) + if(current_address->processed == 0 && current_address->external == NULL) + { + /* Conserve l'offset des Reloc pour l'ExpressLoad */ + if(current_omfsegment->xpress_reloc_offset == 0) + current_omfsegment->xpress_reloc_offset = offset; + + /* Record Type */ + one_byte = 0xF5; /* cRELOC */ + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* Number of Byte to be relocated */ + one_byte = current_address->ByteCnt; + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* Bit Shift Operator */ + one_byte = current_address->BitShiftCnt; + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* Offset of the first Byte to be Patched */ + one_word = current_address->OffsetPatch; + bo_memcpy(&buffer_body[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + /* Address */ + one_word = current_address->OffsetReference; + bo_memcpy(&buffer_body[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + + /* Cette addresse est traitée */ + current_address->processed = 1; + + /* Conserve la longueur des Reloc pour l'ExpressLoad */ + current_omfsegment->xpress_reloc_length += (3*sizeof(BYTE) + 2*sizeof(WORD)); + } + } + + /********************************************************************/ + /*** SUPER, INTERSEG 1 : Adresses Externes, 3 Bytes, pas de Shift ***/ + /********************************************************************/ + if(nb_super_interseg1 > 0) + { + /* Conserve l'offset des Reloc pour l'ExpressLoad */ + if(current_omfsegment->xpress_reloc_offset == 0) + current_omfsegment->xpress_reloc_offset = offset; + + /* Record Type */ + one_byte = 0xF7; /* SUPER : Super Compress Relocation Dictionary */ + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* Length */ + offset_length = offset; + length = 0; + offset += sizeof(DWORD); + /* Type */ + one_byte = 0x02; /* Super Interseg 1 */ + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + + /* Conserve la longueur des Reloc pour l'ExpressLoad */ + current_omfsegment->xpress_reloc_length += (sizeof(BYTE) + sizeof(DWORD) + sizeof(BYTE)); + + /** On va y placer toutes les adresses par Page **/ + current_page = 0x00; + for(nb_address = 0,current_address = current_omfsegment->first_address; current_address; current_address=current_address->next) + if(current_address->processed == 0 && current_address->external != NULL && current_address->ByteCnt == 3 && current_address->BitShiftCnt == 0x00) + { + /* Page de cette addresse */ + address_page = (BYTE) (current_address->OffsetPatch >> 8); + + /* Doit t'on sauter des Pages ? */ + if(address_page != current_page) + { + /* Skip # Pages */ + if(address_page - current_page <= 0x7F) + { + /* 1 seul Byte de Skip Page suffit */ + one_byte = 0x80 | (address_page - current_page); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + } + else + { + /* il faut 2 Bytes de Skip Page */ + one_byte = 0xFF; + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + + one_byte = 0x80 | (address_page - current_page - 0x7F); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + } + + current_page = address_page; + } + + /** On détermine le nombre d'adresse sur cette Page **/ + for(nb_address = 1,next_address = current_address->next; next_address; next_address=next_address->next) + if(next_address->processed == 0 && next_address->external != NULL && next_address->ByteCnt == 3 && next_address->BitShiftCnt == 0x00) + { + if((BYTE) (next_address->OffsetPatch >> 8) == address_page) + nb_address++; + else + break; + } + + /* Nombre d'adresse */ + one_byte = (BYTE) (nb_address-1); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + + /** Liste des addresses de cette Page **/ + for(next_address = current_address; next_address; next_address=next_address->next) + if(next_address->processed == 0 && next_address->external != NULL && next_address->ByteCnt == 3 && next_address->BitShiftCnt == 0x00) + { + if((BYTE) (next_address->OffsetPatch >> 8) == address_page) + { + /* Partie basse de l'adresse */ + one_byte = (BYTE) (0x00FF & next_address->OffsetPatch); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + + /** Modifie les Data au niveau de l'offset en y plaçant l'adresse (on ajoute le delta apporté par l'opération sur le label) **/ + address_patch = next_address->external->external_label->line->address + next_address->OffsetReference; + if(next_address->BitShiftCnt == 0x00) + address_patch |= (((DWORD)(next_address->external->external_segment->segment_number)) << 16); + if(next_address->BitShiftCnt == 0xF0) + address_patch = (address_patch >> 16); + else if(next_address->BitShiftCnt == 0xF8) + address_patch = (address_patch >> 8); + bo_memcpy(&address_path_byte[0],&address_patch,sizeof(DWORD)); + /* Copie à 3 endroits */ + memcpy(&buffer_body[offset_data+next_address->OffsetPatch],&address_path_byte[0],next_address->ByteCnt); /* Dans le LCONST de l'OMF */ + memcpy(¤t_omfsegment->object_code[next_address->OffsetPatch],&address_path_byte[0],next_address->ByteCnt); /* Dans le Code Objet du Segment */ + memcpy(next_address->object_line,&address_path_byte[0],next_address->ByteCnt); /* Dans la line (operand_byte ou data) */ + + /* Cette addresse est traitée */ + next_address->processed = 1; + } + else + break; + } + + /* Page suivante */ + current_page++; + } + + /* Conserve la longueur des Reloc pour l'ExpressLoad */ + current_omfsegment->xpress_reloc_length += length; + + /** Longueur du Super **/ + length += sizeof(BYTE); /* Type */ + bo_memcpy(&buffer_body[offset_length],&length,sizeof(DWORD)); + } + + /************************************************************************/ + /*** SUPER, INTERSEG 13-24 : Adresses Externes, 2 Bytes, pas de Shift ***/ + /************************************************************************/ + for(i=0; i<12; i++) + if(nb_super_interseg_13_24[i] > 0) + { + /* Conserve l'offset des Reloc pour l'ExpressLoad */ + if(current_omfsegment->xpress_reloc_offset == 0) + current_omfsegment->xpress_reloc_offset = offset; + + /* Record Type */ + one_byte = 0xF7; /* SUPER : Super Compress Relocation Dictionary */ + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* Length */ + offset_length = offset; + length = 0; + offset += sizeof(DWORD); + /* Type */ + one_byte = 14+i; /* Super Interseg 13-24 / code 14-25 / Segment 1-12 */ + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + + /* Conserve la longueur des Reloc pour l'ExpressLoad */ + current_omfsegment->xpress_reloc_length += (sizeof(BYTE) + sizeof(DWORD) + sizeof(BYTE)); + + /** On va y placer toutes les adresses par Page **/ + current_page = 0x00; + for(nb_address = 0,current_address = current_omfsegment->first_address; current_address; current_address=current_address->next) + if(current_address->processed == 0 && current_address->external != NULL && current_address->ByteCnt == 2 && current_address->BitShiftCnt == 0x00) + if(current_address->external->external_segment->segment_number == i+1) + { + /* Page de cette addresse */ + address_page = (BYTE) (current_address->OffsetPatch >> 8); + + /* Doit t'on sauter des Pages ? */ + if(address_page != current_page) + { + /* Skip # Pages */ + if(address_page - current_page <= 0x7F) + { + /* 1 seul Byte de Skip Page suffit */ + one_byte = 0x80 | (address_page - current_page); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + } + else + { + /* il faut 2 Bytes de Skip Page */ + one_byte = 0xFF; + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + + one_byte = 0x80 | (address_page - current_page - 0x7F); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + } + + current_page = address_page; + } + + /** On détermine le nombre d'adresse sur cette Page **/ + for(nb_address = 1,next_address = current_address->next; next_address; next_address=next_address->next) + if(next_address->processed == 0 && next_address->external != NULL && next_address->ByteCnt == 2 && next_address->BitShiftCnt == 0x00) + if(next_address->external->external_segment->segment_number == i+1) + { + if((BYTE) (next_address->OffsetPatch >> 8) == address_page) + nb_address++; + else + break; + } + + /* Nombre d'adresse */ + one_byte = (BYTE) (nb_address-1); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + + /** Liste des addresses de cette Page **/ + for(next_address = current_address; next_address; next_address=next_address->next) + if(next_address->processed == 0 && next_address->external != NULL && next_address->ByteCnt == 2 && next_address->BitShiftCnt == 0x00) + if(next_address->external->external_segment->segment_number == i+1) + { + if((BYTE) (next_address->OffsetPatch >> 8) == address_page) + { + /* Partie basse de l'adresse */ + one_byte = (BYTE) (0x00FF & next_address->OffsetPatch); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + + /** Modifie les Data au niveau de l'offset en y plaçant l'adresse (on ajoute le delta apporté par l'opération sur le label) **/ + address_patch = next_address->external->external_label->line->address + next_address->OffsetReference; + if(next_address->BitShiftCnt == 0x00) + address_patch |= (((DWORD)(next_address->external->external_segment->segment_number)) << 16); + if(next_address->BitShiftCnt == 0xF0) + address_patch = (address_patch >> 16); + else if(next_address->BitShiftCnt == 0xF8) + address_patch = (address_patch >> 8); + bo_memcpy(&address_path_byte[0],&address_patch,sizeof(DWORD)); + /* Copie à 3 endroits */ + memcpy(&buffer_body[offset_data+next_address->OffsetPatch],&address_path_byte[0],next_address->ByteCnt); /* Dans le LCONST de l'OMF */ + memcpy(¤t_omfsegment->object_code[next_address->OffsetPatch],&address_path_byte[0],next_address->ByteCnt); /* Dans le Code Objet du Segment */ + memcpy(next_address->object_line,&address_path_byte[0],next_address->ByteCnt); /* Dans la line (operand_byte ou data) */ + + /* Cette addresse est traitée */ + next_address->processed = 1; + } + else + break; + } + + /* Page suivante */ + current_page++; + } + + /* Conserve la longueur des Reloc pour l'ExpressLoad */ + current_omfsegment->xpress_reloc_length += length; + + /** Longueur du Super **/ + length += sizeof(BYTE); /* Type */ + bo_memcpy(&buffer_body[offset_length],&length,sizeof(DWORD)); + } + + /*****************************************************************/ + /*** SUPER, INTERSEG 25-36 : Adresses Externes, 2 Bytes, >> 16 ***/ + /*****************************************************************/ + for(i=0; i<12; i++) + if(nb_super_interseg_25_36[i] > 0) + { + /* Conserve l'offset des Reloc pour l'ExpressLoad */ + if(current_omfsegment->xpress_reloc_offset == 0) + current_omfsegment->xpress_reloc_offset = offset; + + /* Record Type */ + one_byte = 0xF7; /* SUPER : Super Compress Relocation Dictionary */ + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* Length */ + offset_length = offset; + length = 0; + offset += sizeof(DWORD); + /* Type */ + one_byte = 26+i; /* Super Interseg 25-36 / code 26-37 / Segment 1-12 */ + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + + /* Conserve la longueur des Reloc pour l'ExpressLoad */ + current_omfsegment->xpress_reloc_length += (sizeof(BYTE) + sizeof(DWORD) + sizeof(BYTE)); + + /** On va y placer toutes les adresses par Page **/ + current_page = 0x00; + for(nb_address = 0,current_address = current_omfsegment->first_address; current_address; current_address=current_address->next) + if(current_address->processed == 0 && current_address->external != NULL && current_address->ByteCnt == 2 && current_address->BitShiftCnt == 0xF0) + if(current_address->external->external_segment->segment_number == i+1) + { + /* Page de cette addresse */ + address_page = (BYTE) (current_address->OffsetPatch >> 8); + + /* Doit t'on sauter des Pages ? */ + if(address_page != current_page) + { + /* Skip # Pages */ + if(address_page - current_page <= 0x7F) + { + /* 1 seul Byte de Skip Page suffit */ + one_byte = 0x80 | (address_page - current_page); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + } + else + { + /* il faut 2 Bytes de Skip Page */ + one_byte = 0xFF; + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + + one_byte = 0x80 | (address_page - current_page - 0x7F); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + } + + current_page = address_page; + } + + /** On détermine le nombre d'adresse sur cette Page **/ + for(nb_address = 1,next_address = current_address->next; next_address; next_address=next_address->next) + if(next_address->processed == 0 && next_address->external != NULL && next_address->ByteCnt == 2 && next_address->BitShiftCnt == 0xF0) + if(next_address->external->external_segment->segment_number == i+1) + { + if((BYTE) (next_address->OffsetPatch >> 8) == address_page) + nb_address++; + else + break; + } + + /* Nombre d'adresse */ + one_byte = (BYTE) (nb_address-1); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + + /** Liste des addresses de cette Page **/ + for(next_address = current_address; next_address; next_address=next_address->next) + if(next_address->processed == 0 && next_address->external != NULL && next_address->ByteCnt == 2 && next_address->BitShiftCnt == 0xF0) + if(next_address->external->external_segment->segment_number == i+1) + { + if((BYTE) (next_address->OffsetPatch >> 8) == address_page) + { + /* Partie basse de l'adresse */ + one_byte = (BYTE) (0x00FF & next_address->OffsetPatch); + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + length += sizeof(BYTE); + + /** Modifie les Data au niveau de l'offset en y plaçant les 2 octets bas de l'adresse (on ajoute le delta apporté par l'opération sur le label) **/ + address_patch = next_address->external->external_label->line->address + next_address->OffsetReference; + bo_memcpy(&address_path_byte[0],&address_patch,sizeof(DWORD)); + /* Copie à 3 endroits */ + memcpy(&buffer_body[offset_data+next_address->OffsetPatch],&address_path_byte[0],next_address->ByteCnt); /* Dans le LCONST de l'OMF */ + memcpy(¤t_omfsegment->object_code[next_address->OffsetPatch],&address_path_byte[0],next_address->ByteCnt); /* Dans le Code Objet du Segment */ + memcpy(next_address->object_line,&address_path_byte[0],next_address->ByteCnt); /* Dans la line (operand_byte ou data) */ + + /* Cette addresse est traitée */ + next_address->processed = 1; + } + else + break; + } + + /* Page suivante */ + current_page++; + } + + /* Conserve la longueur des Reloc pour l'ExpressLoad */ + current_omfsegment->xpress_reloc_length += length; + + /** Longueur du Super **/ + length += sizeof(BYTE); /* Type */ + bo_memcpy(&buffer_body[offset_length],&length,sizeof(DWORD)); + } + + /*************************************/ + /*** cINTERSEG : Adresses Externes ***/ + /*************************************/ + if(nb_cinterseg > 0) + { + for(current_address = current_omfsegment->first_address; current_address; current_address=current_address->next) + if(current_address->processed == 0 && current_address->external != NULL) + { + /* Conserve l'offset des Reloc pour l'ExpressLoad */ + if(current_omfsegment->xpress_reloc_offset == 0) + current_omfsegment->xpress_reloc_offset = offset; + + /* Record Type */ + one_byte = 0xF6; /* cINTERSEG */ + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* Number of Byte to be relocated */ + one_byte = current_address->ByteCnt; + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* Bit Shift Operator */ + one_byte = current_address->BitShiftCnt; + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* Offset of the first Byte to be Patched */ + one_word = current_address->OffsetPatch; + bo_memcpy(&buffer_body[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + /* Segment Number */ + one_byte = (BYTE) current_address->external->external_segment->segment_number; + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* Address dans un autre Segment */ + one_word = current_address->external->external_label->line->address; + bo_memcpy(&buffer_body[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + + /** Modifie les Data au niveau de l'offset en y plaçant l'adresse (on ajoute le delta apporté par l'opération sur le label) **/ + address_patch = current_address->external->external_label->line->address + current_address->OffsetReference; + if(current_address->BitShiftCnt == 0x00) + address_patch |= (((DWORD)(current_address->external->external_segment->segment_number)) << 16); + if(current_address->BitShiftCnt == 0xF0) + address_patch = (address_patch >> 16); + else if(current_address->BitShiftCnt == 0xF8) + address_patch = (address_patch >> 8); + bo_memcpy(&address_path_byte[0],&address_patch,sizeof(DWORD)); + /* Copie à 3 endroits */ + memcpy(&buffer_body[offset_data+current_address->OffsetPatch],&address_path_byte[0],current_address->ByteCnt); /* Dans le LCONST de l'OMF */ + memcpy(¤t_omfsegment->object_code[current_address->OffsetPatch],&address_path_byte[0],current_address->ByteCnt); /* Dans le Code Objet du Segment */ + memcpy(current_address->object_line,&address_path_byte[0],current_address->ByteCnt); /* Dans la line (operand_byte ou data) */ + + /* Cette addresse est traitée */ + current_address->processed = 1; + + /* Conserve la longueur des Reloc pour l'ExpressLoad */ + current_omfsegment->xpress_reloc_length += (4*sizeof(BYTE) + 2*sizeof(WORD)); + } + } + + /*** END ***/ + one_byte = 0x00; + bo_memcpy(&buffer_body[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + + /* Renvoie la taille du Body */ + return(offset); +} + + +/***************************************************************************************/ +/* RelocateExternalFixedAddress() : On va reloger les valeurs des adresses externes. */ +/***************************************************************************************/ +void RelocateExternalFixedAddress(struct omf_project *current_omfproject, struct omf_segment *current_omfsegment) +{ + DWORD address_patch, org_address, offset_file; + BYTE address_path_byte[4]; + struct relocate_address *current_address; + + /* ORG Adresse du Segment */ + org_address = (current_omfsegment->has_org_address == 1) ? current_omfsegment->org_address : current_omfsegment->org; + + /** On va modifier les adresses faisant référence aux adresses externes **/ + for(current_address = current_omfsegment->first_address; current_address; current_address=current_address->next) + { + /* Internes */ + if(current_address->external == NULL) + continue; + + /** Modifie les Data au niveau de l'offset en y plaçant l'adresse (on ajoute le delta apporté par l'opération sur le label) **/ + address_patch = (current_address->external->external_label->line->bank << 16) | (current_address->external->external_label->line->address + current_address->OffsetReference); + if(current_address->BitShiftCnt == 0xF0) + address_patch = (address_patch >> 16); + else if(current_address->BitShiftCnt == 0xF8) + address_patch = (address_patch >> 8); + bo_memcpy(&address_path_byte[0],&address_patch,sizeof(DWORD)); + + /* Vérifie les dépassements */ + if(current_address->OffsetPatch < (0x0000FFFF & org_address)) + { + printf(" => Error : Can't relocate Address at %04X (Object Org Address is %04X).\n",(int)current_address->OffsetPatch,(int)(0xFFFF & org_address)); + continue; + } + if(current_address->OffsetPatch - (0x0000FFFF & org_address) > (DWORD) current_omfsegment->object_length) + { + printf(" => Error : Can't relocate Address at %04X (Object Length is %04X with Org Address %04X).\n",(int)current_address->OffsetPatch,(int)current_omfsegment->object_length,(int)(0x0000FFFF & org_address)); + continue; + } + + /* Offset depuis le debut du fichier / object_code */ + offset_file = current_address->OffsetPatch - (0x0000FFFF & org_address); + + /* Copie à 2 endroits */ + memcpy(¤t_omfsegment->object_code[offset_file],&address_path_byte[0],current_address->ByteCnt); /* Dans le Code Objet du Segment */ + memcpy(current_address->object_line,&address_path_byte[0],current_address->ByteCnt); /* Dans la line (operand_byte ou data) */ + + /* Information */ + //printf(" => Relocate Address at %04X : %06X (Offset File is %04X).\n",current_address->OffsetPatch,address_patch,offset_file); + } +} + + +/****************************************************/ +/* BuildOMFHeader() : Construction du Header OMF. */ +/****************************************************/ +DWORD BuildOMFHeader(struct omf_project *current_omfproject, struct omf_segment *current_omfsegment) +{ + int i, length; + WORD lab_length; + DWORD offset; + BYTE one_byte; + WORD one_word; + DWORD one_dword; + + /* Init */ + offset = 0; + + /** Remplissage du Header **/ + /* Byte Count (mis à la fin pour tenir compte de la longueur de seg_name */ + offset += sizeof(DWORD); + /* Res Spc */ + one_dword = 0; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + /* Length : Taille du Segment une fois en mémoire = LCONST + DS */ + one_dword = current_omfsegment->object_length; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + /* undefined #1 */ + one_byte = 0x00; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /** LABLEN (0 ou 10) **/ + if(strlen(current_omfsegment->segment_name) <= 10) + one_byte = (BYTE) 0x0A; + else + one_byte = 0x00; /* La longueur su seg_name est codée au début du texte sur 1 octet */ + lab_length = (WORD) one_byte; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* NUMLEN */ + one_byte = 0x04; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* VERSION : 2.1 */ + one_byte = 0x02; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* BANKSIZE */ + one_dword = current_omfsegment->bank_size; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + /* kind */ + one_word = current_omfsegment->type_attributes; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + /* undefined #2 */ + one_byte = 0x00; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* undefined #3 */ + one_byte = 0x00; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* ORG */ + one_dword = current_omfsegment->org; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + /* Align */ + one_dword = current_omfsegment->alignment; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + /* numsex */ + one_byte = 0x00; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* undefined #4 */ + one_byte = 0x00; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* segnum : 1->N (ou 2->N si ExpressLoad) */ + one_word = current_omfsegment->segment_number; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + /* entry */ + one_dword = 0; + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + /* dispname */ + one_word = 0x002C; /* 44 */ + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + /* dispdata */ + one_word = 0x002C + 0x000A + (WORD) ((lab_length == 0) ? (1+strlen(current_omfsegment->segment_name)) : 0x000A); /* 44 + 10 + (10 ou 1+strlen(seg_name)) */ + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + + /* LOAD NAME : 10 bytes */ + length = (int) ((strlen(current_omfsegment->load_name) > 10) ? 10 : strlen(current_omfsegment->load_name)); /* On ne dépasse pas plus de 10 */ + memset(¤t_omfsegment->segment_header_file[offset],0x20,10); + for(i=0; isegment_header_file[offset+i] = current_omfsegment->load_name[i]; + offset += 10; + + /* SEG NAME */ + if(lab_length == 0) + { + /* La longueur est codée sur 1 byte au début */ + one_byte = (BYTE) strlen(current_omfsegment->segment_name); + bo_memcpy(¤t_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + memcpy(¤t_omfsegment->segment_header_file[offset],current_omfsegment->segment_name,strlen(current_omfsegment->segment_name)); + offset += (DWORD) strlen(current_omfsegment->segment_name); + } + else + { + /* lab_length = 10 bytes */ + memset(¤t_omfsegment->segment_header_file[offset],0x20,lab_length); + for(i=0; i<(int)strlen(current_omfsegment->segment_name); i++) + current_omfsegment->segment_header_file[offset+i] = current_omfsegment->segment_name[i]; + offset += lab_length; + } + + /* Byte Count */ + one_dword = offset + current_omfsegment->body_length; + bo_memcpy(¤t_omfsegment->segment_header_file[0],&one_dword,sizeof(DWORD)); + + /** On fait une copie partielle pour l'ExpressLoad **/ + current_omfsegment->header_xpress_length = offset - (3*sizeof(DWORD)); + memcpy(current_omfsegment->header_xpress_file,¤t_omfsegment->segment_header_file[3*sizeof(DWORD)],current_omfsegment->header_xpress_length); + + /* Renvoie la taille du Header */ + return(offset); +} + + +/*******************************************************************/ +/* BuildExpressLoadSegment() : Création du Segment ~ExpressLoad. */ +/*******************************************************************/ +int BuildExpressLoadSegment(struct omf_project *current_omfproject) +{ + int i, offset, file_offset, body_lconst_length; + BYTE one_byte; + WORD one_word; + DWORD one_dword; + char *xpress_name = "~ExpressLoad"; + struct omf_segment *xpress_omfsegment; + struct omf_segment *current_omfsegment; + + /** Allocation mémoire **/ + xpress_omfsegment = mem_alloc_omfsegment(); + if(xpress_omfsegment == NULL) + return(1); + xpress_omfsegment->segment_name = strdup(xpress_name); + if(xpress_omfsegment->segment_name == NULL) + { + /* Libération mémoire */ + mem_free_omfsegment(xpress_omfsegment); + return(1); + } + + /* Attachement en 1ère position */ + current_omfproject->nb_segment++; + xpress_omfsegment->next = current_omfproject->first_segment; + current_omfproject->first_segment = xpress_omfsegment; + + /* ExpressLoad est toujours en 1ère position */ + xpress_omfsegment->segment_number = 1; + + /* Taille des Data du Body de l'ExpressLoad */ + body_lconst_length = sizeof(DWORD) + sizeof(WORD); + for(current_omfsegment=xpress_omfsegment->next; current_omfsegment; current_omfsegment=current_omfsegment->next) + { + body_lconst_length += 2*sizeof(WORD) + sizeof(DWORD); /* Header entry table */ + body_lconst_length += sizeof(WORD); /* Segment Number Conversion Table */ + body_lconst_length += (4*sizeof(DWORD) + current_omfsegment->header_xpress_length); /* Segment Header Table */ + } + + /* Allocation mémoire du Body */ + xpress_omfsegment->segment_body_length = 1024 + body_lconst_length; /* On prend large car on stocke aussi le code du LCONST et le END */ + xpress_omfsegment->segment_body_file = (unsigned char *) calloc(1,xpress_omfsegment->segment_body_length); + if(xpress_omfsegment->segment_body_file == NULL) + return(1); + + /* On connait les tailles du Header et du Body avant de les remplir */ + xpress_omfsegment->header_length = 67; /* 44 + 10 + (1+12) = 67 bytes */ + xpress_omfsegment->body_length = (sizeof(BYTE) + sizeof(DWORD)) + body_lconst_length + sizeof(BYTE); + + /* Offset depuis le début du fichier */ + file_offset = (xpress_omfsegment->header_length + xpress_omfsegment->body_length); + + /*******************************/ + /*** Body de l'ExpressLoad ***/ + /*******************************/ + offset = 0; + + /** LCONST **/ + /* Record Type */ + one_byte = 0xF2; + bo_memcpy(&xpress_omfsegment->segment_body_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* Number of byte */ + one_dword = body_lconst_length; + bo_memcpy(&xpress_omfsegment->segment_body_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + + /** Data **/ + /* Reserved */ + one_dword = 0; + bo_memcpy(&xpress_omfsegment->segment_body_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + /* Number of segments - 1 */ + one_word = current_omfproject->nb_segment - 2; + bo_memcpy(&xpress_omfsegment->segment_body_file[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + /** Header Entry Table **/ + for(current_omfsegment=xpress_omfsegment->next; current_omfsegment; current_omfsegment=current_omfsegment->next) + { + /* Offset relative to segment Header Entry Table */ + one_word = 0; /* Place la vraie valeur plus bas */ + bo_memcpy(&xpress_omfsegment->segment_body_file[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + /* Reserved */ + one_word = 0; + bo_memcpy(&xpress_omfsegment->segment_body_file[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + /* Reserved */ + one_dword = 0; + bo_memcpy(&xpress_omfsegment->segment_body_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + } + /** Segment Number Conversion Table **/ + for(current_omfsegment=xpress_omfsegment->next; current_omfsegment; current_omfsegment=current_omfsegment->next) + { + /* Actual file segment number for original segment */ + one_word = current_omfsegment->segment_number; + bo_memcpy(&xpress_omfsegment->segment_body_file[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + } + /** Segment Header Table **/ + for(i=0,current_omfsegment=xpress_omfsegment->next; current_omfsegment; current_omfsegment=current_omfsegment->next,i++) + { + /* Finalise la valeur : Offset relative to segment Header Entry Table */ + one_word = (WORD) (offset - (sizeof(BYTE) + sizeof(DWORD) + sizeof(DWORD) + sizeof(WORD) + (i*(2*sizeof(WORD) + sizeof(DWORD))))); + bo_memcpy(&xpress_omfsegment->segment_body_file[sizeof(BYTE) + sizeof(DWORD) + sizeof(DWORD) + sizeof(WORD) + i*(2*sizeof(WORD) + sizeof(DWORD))],&one_word,sizeof(WORD)); + + /** Offset et Length des Data et Reloc **/ + current_omfsegment->xpress_data_offset += (current_omfsegment->header_length + file_offset); + bo_memcpy(&xpress_omfsegment->segment_body_file[offset],¤t_omfsegment->xpress_data_offset,sizeof(DWORD)); + offset += sizeof(DWORD); + bo_memcpy(&xpress_omfsegment->segment_body_file[offset],¤t_omfsegment->xpress_data_length,sizeof(DWORD)); + offset += sizeof(DWORD); + current_omfsegment->xpress_reloc_offset += (current_omfsegment->header_length + file_offset); + bo_memcpy(&xpress_omfsegment->segment_body_file[offset],¤t_omfsegment->xpress_reloc_offset,sizeof(DWORD)); + offset += sizeof(DWORD); + bo_memcpy(&xpress_omfsegment->segment_body_file[offset],¤t_omfsegment->xpress_reloc_length,sizeof(DWORD)); + offset += sizeof(DWORD); + + /* Segment #n Header Info */ + memcpy(&xpress_omfsegment->segment_body_file[offset],current_omfsegment->header_xpress_file,current_omfsegment->header_xpress_length); + offset += current_omfsegment->header_xpress_length; + + /* Offset depuis le début du fichier */ + file_offset += (current_omfsegment->header_length + current_omfsegment->body_length); + } + + /** END **/ + one_byte = 0x00; + bo_memcpy(&xpress_omfsegment->segment_body_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + + /*********************************/ + /*** Header de l'ExpressLoad ***/ + /*********************************/ + offset = 0; + /* Segment Header size (ici 67 bytes) + Segment Body size */ + one_dword = 67 + xpress_omfsegment->body_length; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + /* Res Spc */ + one_dword = 0; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + /* Length once in memory = LCONST Size */ + one_dword = xpress_omfsegment->body_length - (sizeof(BYTE) + sizeof(DWORD) + sizeof(BYTE)); /* On enlève la taille de la structure LCONST + END */ + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + /* undefined #1 */ + one_byte = 0x00; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* LABLEN => on met à zéro et on va utiliser un byte en début de chaine de caractère pour indiquer la longueur */ + one_byte = 0; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* NUMLEN */ + one_byte = 0x04; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* VERSION */ + one_byte = 0x02; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* BANKSIZE => 0 pour Data */ + one_dword = 0; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + /* kind = Data (Dynamic + Can be loaded in Special Memory) */ + one_word = 0x8001; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + /* undefined #2 */ + one_byte = 0x00; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* undefined #3 */ + one_byte = 0x00; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* ORG */ + one_dword = 0; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + /* Align */ + one_dword = 0; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + /* numsex */ + one_byte = 0x00; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* undefined #4 */ + one_byte = 0x00; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + /* segnum */ + one_word = 0x0001; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + /* entry */ + one_dword = 0; + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_dword,sizeof(DWORD)); + offset += sizeof(DWORD); + /* dispname */ + one_word = 0x002C; /* 44 */ + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + /* dispdata = Header Size */ + one_word = 0x0043; /* 44 + 10 + 1 + 12=strlen("~ExpressLoad") = 67 */ + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_word,sizeof(WORD)); + offset += sizeof(WORD); + + /* LOAD NAME : 10 bytes à 0x00 */ + for(i=0; i<10; i++) + xpress_omfsegment->segment_header_file[offset+i] = 0x00; + offset += 10; + + /** SEG NAME : 1 byte_length + "~ExpressLoad" **/ + one_byte = (BYTE) strlen(xpress_name); + bo_memcpy(&xpress_omfsegment->segment_header_file[offset],&one_byte,sizeof(BYTE)); + offset += sizeof(BYTE); + memcpy(&xpress_omfsegment->segment_header_file[offset],xpress_name,strlen(xpress_name)); + offset += (int) strlen(xpress_name); + + /* OK */ + return(0); +} + + +/*******************************************************************************/ +/* UpdateFileInformation() : MAJ / Création du fichier _FileInformation.txt. */ +/*******************************************************************************/ +void UpdateFileInformation(char *output_folder_path, char *output_file_name, struct omf_project *current_omfproject) +{ + FILE *fd; + char *next_sep; + int i, nb_line; + BYTE version_created, min_version, access; + char **line_tab; + char file_information_path[1024]; + char file_name[1024]; + char local_buffer[1024]; + char folder_info1[256] = "000000000000000000000000000000000000"; + char folder_info2[256] = "000000000000000000000000000000000000"; + + /* Init */ + version_created = 0x70; + min_version = 0xBE; + access = 0xE3; /* Access Flags : Delete + Rename + Backup + Write + Read */ + + /* Chemin du fichier _FileInformation.txt */ + sprintf(file_information_path,"%s_FileInformation.txt",output_folder_path); + + /** Prépare la ligne du fichier **/ + sprintf(local_buffer,"%s=Type(%02X),AuxType(%04X),VersionCreate(%02X),MinVersion(%02X),Access(%02X),FolderInfo1(%s),FolderInfo2(%s)",output_file_name, + current_omfproject->type,current_omfproject->aux_type,version_created,min_version,access,folder_info1,folder_info2); + + /** Charge en mémoire le fichier **/ + line_tab = BuildUniqueListFromFile(file_information_path,&nb_line); + if(line_tab == NULL) + { + /* Créer le fichier FileInformation */ + CreateBinaryFile(file_information_path,(unsigned char *)local_buffer,(int)strlen(local_buffer)); + + /* Rendre le fichier invisible */ + my_SetFileAttribute(file_information_path,SET_FILE_HIDDEN); + return; + } + + /* Rendre le fichier visible */ + my_SetFileAttribute(file_information_path,SET_FILE_VISIBLE); + + /** Création du fichier **/ + fd = fopen(file_information_path,"w"); + if(fd == NULL) + { + mem_free_list(nb_line,line_tab); + return; + } + + /** Ajouts des lignes existantes **/ + for(i=0; idsk_name_tab) + { + for(i=0; inb_file; i++) + if(current_omfproject->dsk_name_tab[i]) + free(current_omfproject->dsk_name_tab[i]); + free(current_omfproject->dsk_name_tab); + } + + if(current_omfproject->org_address_tab) + free(current_omfproject->org_address_tab); + + if(current_omfproject->file_size_tab) + free(current_omfproject->file_size_tab); + + for(current_omfsegment=current_omfproject->first_segment; current_omfsegment; ) + { + next_omfsegment = current_omfsegment->next; + mem_free_omfsegment(current_omfsegment); + current_omfsegment = next_omfsegment; + } + + if(current_omfproject->project_buffer_file) + free(current_omfproject->project_buffer_file); + + free(current_omfproject); + } +} + + +/******************************************************************************/ +/* mem_alloc_omfsegment() : Allocation mémoire de la structure omf_segment. */ +/******************************************************************************/ +struct omf_segment *mem_alloc_omfsegment(void) +{ + struct omf_segment *current_omfsegment; + + /* Allocation mémoire */ + current_omfsegment = (struct omf_segment *) calloc(1,sizeof(struct omf_segment)); + if(current_omfsegment == NULL) + return(NULL); + + /* Valeurs par defaut */ + current_omfsegment->alignment = ALIGN_NONE; + current_omfsegment->bank_size = 0x10000; /* 64 KB */ + current_omfsegment->org = 0; + current_omfsegment->ds_end = 0; + current_omfsegment->type_attributes = 0x1000; /* Static, Code */ + + /* Initialisation */ + mem_init_omfsegment(current_omfsegment); + + /* Renvoie la structure */ + return(current_omfsegment); +} + + +/*********************************************************************************/ +/* mem_init_omfsegment() : Initialisation mémoire de la structure omf_segment. */ +/*********************************************************************************/ +static void mem_init_omfsegment(struct omf_segment *current_omfsegment) +{ + int i; + + for(i=0; i<1024; i++) + current_omfsegment->alloc_table[i] = NULL; + + current_omfsegment->first_file = NULL; + + current_omfsegment->nb_opcode = 0; + current_omfsegment->first_opcode = NULL; + current_omfsegment->last_opcode = NULL; + current_omfsegment->tab_opcode = NULL; + + current_omfsegment->nb_data = 0; + current_omfsegment->first_data = NULL; + current_omfsegment->last_data = NULL; + current_omfsegment->tab_data = NULL; + + current_omfsegment->nb_directive = 0; + current_omfsegment->first_directive = NULL; + current_omfsegment->last_directive = NULL; + current_omfsegment->tab_directive = NULL; + + current_omfsegment->nb_direqu = 0; + current_omfsegment->first_direqu = NULL; + current_omfsegment->last_direqu = NULL; + current_omfsegment->tab_direqu = NULL; + memset(¤t_omfsegment->local_item,0,sizeof(struct item)); + current_omfsegment->local_item_ptr = ¤t_omfsegment->local_item; + + current_omfsegment->nb_macro = 0; + current_omfsegment->first_macro = NULL; + current_omfsegment->last_macro = NULL; + current_omfsegment->tab_macro = NULL; + memset(¤t_omfsegment->local_macro,0,sizeof(struct macro)); + current_omfsegment->local_macro_ptr = ¤t_omfsegment->local_macro; + + current_omfsegment->nb_label = 0; + current_omfsegment->first_label = NULL; + current_omfsegment->last_label = NULL; + current_omfsegment->tab_label = NULL; + memset(¤t_omfsegment->local_label,0,sizeof(struct label)); + current_omfsegment->local_label_ptr = ¤t_omfsegment->local_label; + + current_omfsegment->nb_equivalence = 0; + current_omfsegment->first_equivalence = NULL; + current_omfsegment->last_equivalence = NULL; + current_omfsegment->tab_equivalence = NULL; + memset(¤t_omfsegment->local_equivalence,0,sizeof(struct equivalence)); + current_omfsegment->local_equivalence_ptr = ¤t_omfsegment->local_equivalence; + + current_omfsegment->nb_variable = 0; + current_omfsegment->first_variable = NULL; + current_omfsegment->last_variable = NULL; + current_omfsegment->tab_variable = NULL; + memset(¤t_omfsegment->local_variable,0,sizeof(struct variable)); + current_omfsegment->local_variable_ptr = ¤t_omfsegment->local_variable; + + current_omfsegment->nb_external = 0; + current_omfsegment->first_external = NULL; + current_omfsegment->last_external = NULL; + current_omfsegment->tab_external = NULL; + memset(¤t_omfsegment->local_external,0,sizeof(struct external)); + current_omfsegment->local_external_ptr = ¤t_omfsegment->local_external; +} + + +/*****************************************************************************/ +/* mem_free_omfsegment() : Libération mémoire de la structure omf_segment. */ +/*****************************************************************************/ +void mem_free_omfsegment(struct omf_segment *current_omfsegment) +{ + int i; + struct relocate_address *current_address; + struct relocate_address *next_address; + + if(current_omfsegment) + { + /** Header **/ + if(current_omfsegment->master_file_path) + free(current_omfsegment->master_file_path); + + if(current_omfsegment->load_name) + free(current_omfsegment->load_name); + + if(current_omfsegment->segment_name) + free(current_omfsegment->segment_name); + + /** Code Objet **/ + for(current_address=current_omfsegment->first_address; current_address; ) + { + next_address = current_address->next; + free(current_address); + current_address = next_address; + } + + if(current_omfsegment->object_code) + free(current_omfsegment->object_code); + + if(current_omfsegment->segment_body_file) + free(current_omfsegment->segment_body_file); + + /** Zones mémoires **/ + my_Memory(MEMORY_FREE_OPCODE,NULL,NULL,current_omfsegment); + my_Memory(MEMORY_FREE_DATA,NULL,NULL,current_omfsegment); + my_Memory(MEMORY_FREE_DIRECTIVE,NULL,NULL,current_omfsegment); + my_Memory(MEMORY_FREE_DIREQU,NULL,NULL,current_omfsegment); + my_Memory(MEMORY_FREE_MACRO,NULL,NULL,current_omfsegment); + my_Memory(MEMORY_FREE_LABEL,NULL,NULL,current_omfsegment); + my_Memory(MEMORY_FREE_EQUIVALENCE,NULL,NULL,current_omfsegment); + my_Memory(MEMORY_FREE_VARIABLE,NULL,NULL,current_omfsegment); + my_Memory(MEMORY_FREE_EXTERNAL,NULL,NULL,current_omfsegment); + my_Memory(MEMORY_FREE_GLOBAL,NULL,NULL,current_omfsegment); + my_Memory(MEMORY_FREE_FILE,NULL,NULL,current_omfsegment); + + /* Libère toutes les allocations temporaires */ + for(i=0; i<1024; i++) + if(current_omfsegment->alloc_table[i] != NULL) + { + free(current_omfsegment->alloc_table[i]); + current_omfsegment->alloc_table[i] = NULL; + } + + /* Libère la structure */ + free(current_omfsegment); + } +} + +/***********************************************************************/ diff --git a/Source/a65816_OMF.h b/Source/a65816_OMF.h new file mode 100644 index 0000000..036ea83 --- /dev/null +++ b/Source/a65816_OMF.h @@ -0,0 +1,177 @@ +/***********************************************************************/ +/* */ +/* a65816_OMF.h : Header pour la gestion du fichier OMF. */ +/* */ +/***********************************************************************/ +/* Auteur : Olivier ZARDINI * Brutal Deluxe Software * Janv 2011 */ +/***********************************************************************/ + +#define CRECORD_SIZE 7 /* Taille d'un CRecord */ +#define END_SIZE 1 /* Taille d'un END */ + +struct omf_project +{ + BYTE type; /* Type du fichier ($06 pour les Multi-Segment Fixed-Address) */ + WORD aux_type; /* AuxType du fichier */ + int express_load; /* Ajoute le Segment ExpressLoad au début */ + + /** Liste des Fichiers Multi-Segments (OMF ou Fixed Address) **/ + int nb_file; /* Nombre de fichiers pour les Multi-Segment Fixed-Address OneBinaryFile */ + char **dsk_name_tab; /* Nom du projet = Nom du fichier à créer (en OMF ou en Multi-Segment Fixed-Address SingleBinary) */ + DWORD *org_address_tab; /* Pour les Multi-Segment Fixed-Address OneBinaryFile, le ORG est fixé par le fichier LINK */ + DWORD *file_size_tab; /* Taille des fichiers pour les Multi-Segment Fixed-Address OneBinaryFile */ + + /** Liste des Segments OMF / Fixed Address **/ + int nb_segment; + struct omf_segment *first_segment; + struct omf_segment *last_segment; + + /** Data du Projet **/ + DWORD project_buffer_length; + unsigned char *project_buffer_file; + + /* Taille du fichier Projet */ + DWORD project_file_length; + + /* Type de Program */ + int is_omf; /* Il s'agit d'un projet Relogeable OMF v2.1 */ + int is_multi_fixed; /* Il s'agit d'un projet Multi-Segment Fixed-Address */ + int is_single_binary; /* A la fin, on colle tous les segments Fixed-Address ensemble, les uns derrière les autres (dans 1 ou plusieurs fichiers) */ +}; + +#define ALIGN_BANK 2 +#define ALIGN_PAGE 1 +#define ALIGN_NONE 0 + +struct omf_segment +{ + char *master_file_path; /* Chemin du fichier Source Master */ + + /*****************************************************/ + /* Valeurs utilisées dans le Header du Segment OMF */ + /*****************************************************/ + WORD type_attributes; /* Type + Attributs */ + int bank_size; /* Baznk Size (64KB for code, 0-64 KB for Data, O=can cross boundaries) */ + int org; /* Absolute address to load the segment, 0=anywhere */ + int alignment; /* Boundary Alignement */ + int ds_end; /* Nombre de 0 à ajouter à la fin du Segment */ + + char *load_name; + char *segment_name; + + int file_number; /* Numéro du fichier (pour les Fixed-Address Single-Binary */ + + /***************************************************/ + /* Valeurs utilisées dans le Body du Segment OMF */ + /***************************************************/ + /* Numéro du Segment */ + int segment_number; /* 1-N */ + + /* Pour les Multi-Segment Fixed-Address OneBinaryFile, le ORG est fixé par le fichier LINK */ + int has_org_address; + DWORD org_address; + + /* Type de fichier en sortie : OMF ou Binaire */ + int is_omf; + int is_relative; /* On a un REL => Pas de Direct Page pour les Label (sauf si l'assemblage est géré via un Link.txt Fixed Address) */ + + /** Liste des addresses à patcher **/ + int nb_address; + struct relocate_address *first_address; + struct relocate_address *last_address; + + /* Fichier a créer */ + char object_name[256]; + + /* Object code */ + int object_length; + unsigned char *object_code; + + /*** Données du Segment : Header + Body ***/ + DWORD header_length; + unsigned char segment_header_file[1024]; /* On prend large */ + + DWORD segment_body_length; /* Taille de la zone allouée */ + DWORD body_length; + unsigned char *segment_body_file; + + /* Header stocké dans l'ExpressLoad */ + DWORD xpress_data_offset; + DWORD xpress_data_length; + DWORD xpress_reloc_offset; + DWORD xpress_reloc_length; + + DWORD header_xpress_length; + unsigned char header_xpress_file[1024]; /* On prend large */ + + /************************************************/ + /* Ensemble des structures de données mémoire */ + /************************************************/ + void *alloc_table[1024]; + struct source_file *first_file; /* Premier fichier source */ + int nb_opcode; /* Liste des opcode */ + struct item *first_opcode; + struct item *last_opcode; + struct item **tab_opcode; + int nb_data; /* Liste des data */ + struct item *first_data; + struct item *last_data; + struct item **tab_data; + int nb_directive; /* Liste des directive */ + struct item *first_directive; + struct item *last_directive; + struct item **tab_directive; + int nb_direqu; /* Liste des directive equivalence */ + struct item *first_direqu; + struct item *last_direqu; + struct item **tab_direqu; + struct item local_item; + struct item *local_item_ptr; + int nb_macro; /* Liste des macro */ + struct macro *first_macro; + struct macro *last_macro; + struct macro **tab_macro; + struct macro local_macro; + struct macro *local_macro_ptr; + int nb_label; /* Liste des label */ + struct label *first_label; + struct label *last_label; + struct label **tab_label; + struct label local_label; + struct label *local_label_ptr; + int nb_equivalence; /* Liste des equivalence */ + struct equivalence *first_equivalence; + struct equivalence *last_equivalence; + struct equivalence **tab_equivalence; + struct equivalence local_equivalence; + struct equivalence *local_equivalence_ptr; + int nb_variable; /* Liste des variable */ + struct variable *first_variable; + struct variable *last_variable; + struct variable **tab_variable; + struct variable local_variable; + struct variable *local_variable_ptr; + int nb_external; /* Liste des external EXT */ + struct external *first_external; + struct external *last_external; + struct external **tab_external; + struct external local_external; + struct external *local_external_ptr; + int nb_global; /* Liste des global ENT */ + struct global *first_global; + struct global *last_global; + + struct omf_segment *next; +}; + +DWORD BuildOMFHeader(struct omf_project *,struct omf_segment *); +DWORD BuildOMFBody(struct omf_project *,struct omf_segment *); +void RelocateExternalFixedAddress(struct omf_project *,struct omf_segment *); +int BuildOMFFile(char *,struct omf_project *); +int BuildExpressLoadSegment(struct omf_project *); +void UpdateFileInformation(char *,char *,struct omf_project *); +void mem_free_omfproject(struct omf_project *); +struct omf_segment *mem_alloc_omfsegment(void); +void mem_free_omfsegment(struct omf_segment *); + +/***********************************************************************/ diff --git a/Source/linux_makefile b/Source/linux_makefile new file mode 100644 index 0000000..f5504e4 --- /dev/null +++ b/Source/linux_makefile @@ -0,0 +1,14 @@ +CC = gcc +CFLAGS += -Icompat -Werror -DUNIX + +SOURCES = a65816_Code.c a65816_Cond.c a65816_Data.c a65816_File.c \ + a65816_Line.c a65816_Link.c a65816_Lup.c a65816_Macro.c a65816_OMF.c \ + Dc_Library.c Main.c + +OBJECTS=$(SOURCES:.c=.o) + +Merlin32: $(OBJECTS) + gcc $^ -o $@ + +clean: + rm -f $(OBJECTS) Merlin32