For AMIGA-Heads Only...
This code is purely for a minimum of a stock Classic AMIGA A1200(HD), E-UAE, and WinUAE running AMIGA OS3.0x to 3.1x. It will NOT work on any other platform!
(It MIGHT work on AMIGA OS3.5x and 3.9x with Python 2.4.6, but totally untested and I hold no responsibility for the outcome when trying it.)
It is a DEMO to peek a byte inside _ANY_ memory address inside the standard CPU 68EC020 16MB boundary.
I experimented with this several years ago and have decided to finally release it. I do await the flak!
It works from Python Versions 1.4.0 to 2.0.1 for the classic AMIGA.
Ensure that the T: Volume exists on the running machine.
See inside the code and text below it also as to how it works...
Bazza, G0LCU...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | # AMIGA_Peek_Mem.py
#
# DEMO code to show how to peek/read a single BYTE from any address for the
# Classic AMIGA A1200(HD), E-UAE and WinUAE. Although the code only does BYTE
# depth it is easily possible to add, WORD length, (I've already done so).
# (Soon there will be a demo to poke/write to a memory or HW address inside the
# Classic AMIGA too.)
#
# Originally written for a standard AMIGA A1200 using Python 1.4.x to 2.0.1.
# $VER: AMIGA_Peek_Mem.py_Version_0.00.10_(C)2007-2012_B.Walker_G0LCU.
#
# Doing the 256 byte dump in this DEMO is slow but this function was not
# originally designed for that facility but to quickly view the byte contents
# of a single memory address. To work correctly this MUST be run from a "tool"
# icon so that any AMIGA return code Failat reports are directed to the system
# "stderr" rather than the default Python window...
#
# Now issued as Public Domain. You may do with it as you please...
#
# =============================================================================
#
# ; The assembly code for this Python script, peek.asm...
# ; Assembled using a68k and linked using blink, both are on AMINET.
# lea.l $00F80000,a5 ;Set address to the default start of ROM.
# move.b (a5),d0 ;Move byte contents of the address into register d0.
# rts ;Now return to calling routine with the byte value.
# nop ;Long word align code.
# even ;Done!
# end ;This will also compile with DevPac too!
# ; Yep, that's all there is to it... ;o)
#
# =============================================================================
#
# The binary, (peek), generated from the assembly code converted to text format using:-
# AMIGA_Prompt: C:Type HEX peek > peek.HEX<CR>
#
# The text HEX file representing the AMIGA executable to be edited...
# 0000: 000003F3 00000000 00000001 00000000 ...ó............
# 0010: 00000000 00000003 000003E9 00000003 ...........é....
# 0020: 4BF900F8 00001015 4E754E71 000003F2 Kù.ü....NuNq...ò
#
# =============================================================================
#
# This is the 256 byte ROM DUMP at address $00F80000...
#
# 0000: 11144EF9 00F800D2 0000FFFF 00280044 ..Nù.ø.Ò.....(.D
# 0010: 0028000A FFFFFFFF 00414D49 47412052 .(.......AMIGA R
# 0020: 4F4D204F 70657261 74696E67 20537973 OM Operating Sys
# 0030: 74656D20 616E6420 4C696272 61726965 tem and Librarie
# 0040: 7300436F 70797269 67687420 A9203139 s.Copyright © 19
# 0050: 38352D31 39393320 00436F6D 6D6F646F 85-1993 .Commodo
# 0060: 72652D41 6D696761 2C20496E 632E2000 re-Amiga, Inc. .
# 0070: 416C6C20 52696768 74732052 65736572 All Rights Reser
# 0080: 7665642E 00332E31 20524F4D 20006578 ved..3.1 ROM .ex
# 0090: 65632E6C 69627261 72790065 78656320 ec.library.exec
# 00A0: 34302E31 30202831 352E372E 3933290D 40.10 (15.7.93).
# 00B0: 0A004E71 4E714AFC 00F800B6 00F8370E ..NqNqJü.ø.¶.ø7.
# 00C0: 02280969 00F8008E 00F8009B 00F804AC .(.i.ø...ø...ø.¬
# 00D0: 4E704FF8 040041FA FF2872FF 75017B00 NpOø..Aú.(r.u.{.
# 00E0: DA986402 528551C9 FFF851CA FFF44BFA Ú.d.R.QÉ.øQÊ.ôKú
# 00F0: 001A41FA FF0C43F9 00F00000 B3C8670A ..Aú..Cù.ð..³Èg.
#
# =============================================================================
#
# After finding the address of the string, ~find_this_text~ using the id()
# function, this was the RAM DUMP for Python Version 1.4.0 on my test machine.
#
# 0000: 00000002 002B8290 00000072 FFFFFFFF .....+.....r....
# 0010: 57652077 696C6C20 75736520 74686520 We will use the
# 0020: 69642829 2066756E 6374696F 6E20746F id() function to
# 0030: 2066696E 64207468 6973206C 696E6520 find this line
# 0040: 6C617465 722E2054 68652074 68696E67 later. The thing
# 0050: 2069732C 20796F75 2043414E 20646F20 is, you CAN do
# 0060: 74686973 20776974 6820616E 20414D49 this with an AMI
# 0070: 47412057 4954484F 55542061 6E204D4D GA WITHOUT an MM
# 0080: 5521004E 00000020 00000002 002B8290 U!.N... .....+..
# 0090: 0000000E 123E7734 66696E64 5F746869 .....>w4find_thi
# 00A0: 735F7465 78740008 00000000 00000019 s_text..........
# 00B0: 00000001 002B8290 00000007 FFFFFFFF .....+..........
# 00C0: 64656670 61746800 0030494C 00000018 defpath..0IL....
# 00D0: 00000001 002B8290 00000006 FFFFFFFF .....+..........
# 00E0: 73747269 6E67000F 00030030 0000001D string.....0....
# 00F0: 00000001 002B8290 0000000B FFFFFFFF .....+..........
#
# =============================================================================
#
# Again, finding the address of the string, ~find_this_text~ using the id()
# function, this was the RAM DUMP for Python Version 2.0.1 on my test machine.
#
# 0000: 00000002 0032956C 00000072 FBA7A5FC .....2.l...rû§¥ü
# 0010: 00000000 57652077 696C6C20 75736520 ....We will use
# 0020: 74686520 69642829 2066756E 6374696F the id() functio
# 0030: 6E20746F 2066696E 64207468 6973206C n to find this l
# 0040: 696E6520 6C617465 722E2054 68652074 ine later. The t
# 0050: 68696E67 2069732C 20796F75 2043414E hing is, you CAN
# 0060: 20646F20 74686973 20776974 6820616E do this with an
# 0070: 20414D49 47412057 4954484F 55542061 AMIGA WITHOUT a
# 0080: 6E204D4D 55210000 00000085 00000024 n MMU!.........$
# 0090: 00000004 0032956C 0000000E 123E7734 .....2.l.....>w4
# 00A0: 0038A16C 66696E64 5F746869 735F7465 .8¡lfind_this_te
# 00B0: 78740001 00000000 000000C8 00329DA8 xt.........È.2.š
# 00C0: 00000009 0038C10C 00000000 00000013 .....8Á.........
# 00D0: 01240000 00000000 00870000 00010038 .$.............8
# 00E0: A1C40123 0038A250 00000060 00000000 ¡Ä.#.8¢P...`....
# 00F0: 00870000 00010038 A1DC0000 0038A250 .......8¡Ü...8¢P
#
# =============================================================================
print "\f\n$VER: AMIGA_Peek_Mem.py_Version_0.00.10_(C)2007-2012_B.Walker_G0LCU."
print "\nPlease wait..."
import os
import struct
find_this_text="We will use the id() function to find this line later. The thing is, you CAN do this with an AMIGA WITHOUT an MMU!"
# The only important _variable_.
global return_code
return_code=0
# Default to the start of the ROM, 0xF80000.
def peek(address=16252928):
global return_code
return_code=0
# Don't allow any errors......
address=int(address)
# ......although this should NEVER occur...
if address<=0: address=0
# Limit to standard AMIGA A1200(HD) 16MB boundary for this DEMO.
if address>=16777215: address=16777215
# Generate the 32 bit address as a string...
address_string=struct.pack("l",address)
start_peek_string="\x00\x00\x03\xF3\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x03\xE9\x00\x00\x00\x03\x4B\xF9"
end_peek_string="\x10\x15\x4E\x75\x4E\x71\x00\x00\x03\xF2"
# Now create the AMIGA file that will be executed...
peek_address_string=start_peek_string+address_string+end_peek_string
# Generate the file inside the T: Volume, usually a RamDisk...
amigafile=open("T:PeekMem","wb+")
amigafile.write(peek_address_string)
amigafile.close()
# Ensure the file is executable; return_code is ignored here...
return_code=os.system("C:Protect T:PeekMem rwed")
# Run the AMIGA executable and get the return_code as a byte value...
return_code=os.system("T:PeekMem")
# We now have our byte read from memory _address_...
return(return_code)
# Start of the DEMO using the peek() function.
# Do a single byte dump only for a start, it is effectively a Failat return code but
# it is redirected to the system's stderr so it is NOT seen on a default Python window...
print "\f\nFirstly, do a single byte dump at the AMIGA ROM address 16777215, $FFFFFF..."
address=16777215
return_code=peek(address)
print "\nByte value at the last odd address, $FFFFFF in the AMIGA ROM is "+str(return_code)+"...\n"
raw_input("Press <CR> to continue...")
# Access the function 256 times, this is slow, but hey, peeking memory by
# the back door cannot be bad, can it?
# Using the same address value as the default...
print "\f\nDo a 256 byte dump of the AMIGA ROM at the default address, $F80000..."
address=16252928
peeked_address=""
for n in range(address,(address+256),1):
return_code=peek(n)
peeked_address=peeked_address+chr(return_code)
# Generate the binary file as a file and autosave...
amigafile=open("T:Binary.BIN","wb+")
amigafile.write(peeked_address)
amigafile.close()
# Now convert to a text HEX version of the binary file inside the T: Volume.
os.system("C:Type HEX T:Binary.BIN > T:Binary.HEX")
# The return_code is directed to the system's stderr, so this ensures that
# the dump can be printed to the default Python window...
amigafile=open("T:Binary.HEX","r+")
peeked_address=amigafile.read()
amigafile.close()
# Print the dump to screen...
print "\f\nStart address of the 256 byte ROM dump is "+str(address)+", "+hex(address)+"...\n"
print peeked_address
raw_input("Press <CR> to continue...")
# Do the same again but this time find the _address_ of id(find_this_text)...
print "\f\nNow to find the address of the string _variable_ ~find_this_text~..."
address=id(find_this_text)
peeked_address=""
for n in range(address,(address+256),1):
return_code=peek(n)
peeked_address=peeked_address+chr(return_code)
amigafile=open("T:Binary.BIN","wb+")
amigafile.write(peeked_address)
amigafile.close()
os.system("C:Type HEX T:Binary.BIN > T:Binary.HEX")
amigafile=open("T:Binary.HEX","r+")
peeked_address=amigafile.read()
amigafile.close()
print "\f\nStart address of the 256 byte dump is "+str(address)+", "+hex(address)+"...\n"
print peeked_address+"\nEnd of the function, peek(), DEMO..."
# End of AMIGA_Peek_Mem.py DEMO.
# Enjoy finding simple solutions to often very difficult problems...
|
How it works:-
I suspect this will raise a few eyebrows but here goes...
The original idea was to find out exactly where a string was in memory just for fun, fill it with a binary executable then finding a way of calling that executable to hit the AMIGA HW directly... (NOTE:- This idea DOES work on this particular platform!)
The first few lines of non-commented code are just the usual type of lines needed to run correctly inside the lowest Python Version.
Next is the peek() function whose default address is the start of ROM at $F80000.
On calling this function any address that is entered is corrected to be kept inside the limits shown and converted to into a 4 byte string. A new string is now generated with these four characters inside the new string and a file created and saved to the T: Volume as PeekMem. It is then made executable and run...
Now the eyebrow bit... ;o)
The byte value read in this new executable is a return code and is passed back to the Python code for printing to the screen if required.
Now the first part reads the last byte in ROM at odd address $FFFFFF as this is what the function was intended for, single byte read, however......
In the DEMO a 256 byte dump is generated next and although it is slow, (remember a stock AMIGA A1200(HD) does NOT run at several GHz but at 14MHz), is saved as a Binary.BIN file then converted to Binary.HEX, a pure text file. This method was to ensure printing to the screen ALWAYS worked from the default "Tool" icon.
With user intervention the same is done again but the address of the string inside the Python code is found using the id() function. I now have the address exactly by _viewing_ the offset value and adding it to the id() function value generated. I DO have another version of _peek_ which was uploaded to AMINET some years ago but nothing like this. I kept this one to myself but have now decided to let it go for AMIGA community.
I will be releasing a DEMO poke_(ing) a single byte into a memory address for the Classic AMIGA A1200(HD) in the not too distant future...
Have fun finding simple solutions to often very difficult problems... ;o)
Bazza, G0LCU...