namespace icd2 { namespace vram { let BUFFER_COUNT = 4; let BUFFER_BYTE_SIZE = 320; let BUFFER_INDEX_MASK = 3; // The tile row is the current GB scanline divided by 8. // Every time the tile row increases, the buffer index is advanced. // The buffer index is between 0 .. 3 and will wrap around. // The GB screen is 144 pixels, or 18 rows tall. // During vblank, the PPU will be on tile row 18. // While the tile row will reset to 0 when starting a new frame, the buffer index to be written carries across frames. // Since 18 / 4 has a remaninder of 2, this means the buffer index can be either buffer 0 or buffer 2 at the start of a new frame. // // It should be possible to read the buffer for the first row tiles when the PPU position reaches tile row 1, meaning tile row 0 was just fully drawn? // // The safest position to read appears the index immediately before the write position, since it gives the most time read the row without being written over. // If the SNES side can keep up fast, maybe could do 2 rows behind and read both without re-checking PPU position, but seems potentially more risky. Hmm. const ppu_position @ 0x6000 : u8; let PPU_POSITION_TILE_ROW_MASK = 0xF8; let PPU_POSITION_TILE_ROW_SHIFT = 3; let PPU_POSITION_BUFFER_INDEX_MASK = 0x3; // Selects which of the buffers 0 .. 3 to read from, and resets the position in the buffer. writeonly read_buffer_index @ 0x6001 : u8; // Port to read the next value from the VRAM. The GB screen is 160 pixels, or 20 columns wide. // The data port will have 2 bytes/row * 8 rows/tile * 20 tiles = 320 bytes of data for a given buffer. const read_data @ 0x7800 : u8; } namespace command { const ready @ 0x6002 : u8; const data @ 0x7000 : [u8; 16]; } namespace joy { namespace bit { let RIGHT = 0; let LEFT = 1; let UP = 2; let DOWN = 3; let A = 4; let B = 5; let SELECT = 6; let START = 7; } namespace mask { let RIGHT = 0x01; let LEFT = 0x02; let UP = 0x04; let DOWN = 0x08; let A = 0x10; let B = 0x20; let SELECT = 0x40; let START = 0x80; } writeonly data1 @ 0x6004 : u8; writeonly data2 @ 0x6005 : u8; writeonly data3 @ 0x6006 : u8; writeonly data4 @ 0x6007 : u8; } writeonly ctrl @ 0x6003 : u8; let CTRL_RESET = 0x80; let CTRL_JOY_MODE_4P = 0x20; let CTRL_JOY_MODE_2P = 0x10; let CTRL_JOY_MODE_1P = 0x00; let CTRL_SPEED_VERY_SLOW = 0x03; let CTRL_SPEED_SLOW = 0x02; let CTRL_SPEED_NORMAL = 0x01; let CTRL_SPEED_FAST = 0x00; const version @ 0x600F : u8; }import os import os.path import PIL.Image def write_chr(w, h, data, f): for y in range(0, h, 8): for x in range(0, w, 8): for j in range(8): # Write bit 0 of all columns in this row. c = 0 for i in range(8): c = (c * 2) | (data[x + i, y + j] & 1) f.write(bytearray([c])) # Write bit 1 of all columns in this row. c = 0 for i in range(8): c = (c * 2) | ((data[x + i, y + j] >> 1) & 1) f.write(bytearray([c])) for j in range(8): # Write bit 2 of all columns in this row. c = 0 for i in range(8): c = (c * 2) | ((data[x + i, y + j] >> 2) & 1) f.write(bytearray([c])) # Write bit 3 of all columns in this row. c = 0 for i in range(8): c = (c * 2) | ((data[x + i, y + j] >> 3) & 1) f.write(bytearray([c])) if __name__ == '__main__': import sys if len(sys.argv) > 1: WIDTH = 128 HEIGHT = None for arg in range(1, len(sys.argv)): filename = sys.argv[arg] if filename[0] == '-': if filename == '-oldfart': HEIGHT = 192 elif filename == '-newfart': HEIGHT = None else: exit('Invalid argument `' + filename + '`.') continue try: img = PIL.Image.open(filename) except IOError as e: if os.path.isdir(filename): exit(filename + ' is a directory.') if os.path.exists(filename): exit(filename + ' has an unsupported filetype, or you lack permission to open it.') else: exit('File ' + filename + ' does not exist!') w, h = img.size if w != WIDTH or h % 8 != 0 or HEIGHT and h != HEIGHT: exit('Image ' + filename + ' is not ' + str(WIDTH) + 'x' + str(HEIGHT) + ' pixels in size.') if not img.palette: exit('Image ' + filename + ' has no palette.') data = img.load() save_filename = os.path.splitext(filename)[0] + '.chr' try: f = open(save_filename, 'wb') except Exception as e: exit('Failure attempting to write ' + save_filename) write_chr(w, h, data, f) f.close() print(' ' + filename + ' -> ' + save_filename) else: print('Usage: ' + sys.argv[0] + ' file [file...]') print('Converts files like foo.png into SNES-friendly formats like foo.chr') PNG  IHDR1|,tEXtCreation TimeTue 15 Feb 2011 18:41:59 -0500tIME$T pHYs B4gAMA a0PLTE#I, pVZIDATxVb xcWaƯ'7ilˆm ~W DjuVU("> Aj;pQ0]pI#&/]0cKT,ߖ"xn9ԪC+clv&+ @f՗àwt;bcej o|_$T]r[6P[Ul QKs:Z?r-gfj %^#!.pX0ӈ|Qbb)dwfF-"%|ON}'SKLPCC/^0Q c4Vi\FG q>ETgc{D{\J*J>J71d Re>+ hۅu/suV^̣+JAtT^(YƢԯ, 8Ť>\T;-" 2MϞ;>LSꤒEwoLK>:b|!mc^hgxkagEѱYnxt9;;vUo8,ёYX[R ^?҃h}\2*} c 7>P M6cg'Nn:.DJ21dډ*q>zTlk a+npv#)^uB{| ;AT8%!| m!LغLLφ]·w5{=lNl}u+í|8e@FPDnl1KPy ˈJ) 2p,η3T/ʶj7A8:i98QNn D&&bπ8Ӓ}BNp1Y8@kkkkksIENDB`PNG  IHDR%tIME%Ѭ pHYs B4gAMA a0PLTEO&IIDATxڅS  ;KjWD"}Jw?qs< 1㠙ebe `! @Ʈ8##%`plg:JL03*l *|Qq#a+8vlጱ #K񵘫|=CLg2i@nSG8T/} Bozž5Mq =Ⱥʵp=}w;RBOV2o19b! M0JTDJ#1]"Yw = 7x,X#O w={('LZ`8u>xIco@ r7J%n_t.^|#ZQXHu̱ mfy%mtIENDB`88|Ld|8888LLdd88888<<<88<<||><|`||<<``||><>||||<<||<<|l <V=BgP$J{i:6}c[qLxDM[be;du{x?dh$ʵ~p&=} ;ga? Zy!Ps$>Ob<|`||<<``||><>||||<<||<<|l < i24 multiplier. Only available with mode-7 disabled. // Write left, then right. Result should be available immediately. namespace multiply_i16i8 { extern writeonly left @ 0x211B : u8; // 2x write extern writeonly right @ 0x211C : u8; extern const result_l @ 0x2134 : u8; extern const result_m @ 0x2135 : u8; extern const result_h @ 0x2136 : u8; extern const result_ml @ 0x2134 : u16; extern const result_hm @ 0x2135 : u16; } // u8 x u8 -> u16 multiplier. // Write left, then right. // 8 machine cycles (~48 master cycles) after right is set, the result may be read. namespace multiply_u8u8 { extern writeonly left @ 0x4202 : u8; extern writeonly right @ 0x4203 : u8; extern const result_l @ 0x4216 : u8; extern const result_h @ 0x4217 : u8; extern const result_hl @ 0x4216 : u16; } // u16 / u8 -> (u16, u16) divider. // Write left, then right. // 16 machine cycles (~96 master cycles) after right is set, the result may be read. namespace divider { extern writeonly left_l @ 0x4204 : u8; extern writeonly left_h @ 0x4205 : u8; extern writeonly left_hl @ 0x4204 : u16; extern writeonly right @ 0x4206 : u8; extern const div_result_l @ 0x4214 : u8; extern const div_result_h @ 0x4215 : u8; extern const div_result_hl @ 0x4214 : u16; extern const mod_result_l @ 0x4216 : u8; extern const mod_result_h @ 0x4217 : u8; extern const mod_result_hl @ 0x4216 : u16; } namespace rom { extern writeonly speed @ 0x420D : u8; let SPEED_SLOW = 0; let SPEED_FAST = 1; } namespace dma { extern writeonly mdma_enable @ 0x420B : u8; extern writeonly hdma_enable @ 0x420C : u8; let ENABLE_0 = 0b00000001; let ENABLE_1 = 0b00000010; let ENABLE_2 = 0b00000100; let ENABLE_3 = 0b00001000; let ENABLE_4 = 0b00010000; let ENABLE_5 = 0b00100000; let ENABLE_6 = 0b01000000; let ENABLE_7 = 0b10000000; let CONTROL_MODE_MASK = 0x07; let CONTROL_MODE_A = 0x00; let CONTROL_MODE_AB = 0x01; let CONTROL_MODE_AA = 0x02; let CONTROL_MODE_AABB = 0x03; let CONTROL_MODE_ABCD = 0x04; let CONTROL_MODE_ABAB = 0x05; let CONTROL_MDMA_DECREMENT = 0x10; let CONTROL_MDMA_NO_INCREMENT = 0x08; let CONTROL_HDMA_INDIRECT_MODE = 0x40; let CONTROL_READ_PPU = 0x80; let HDMA_LINE_COUNTER_COUNT_MASK = 0x7F; let HDMA_LINE_COUNTER_REPEATED = 0x80; } namespace dma0 { extern writeonly control @ 0x4300 : u8; extern writeonly mdma_dest @ 0x4301 : u8; extern writeonly src_address_l @ 0x4302 : u8; extern writeonly src_address_h @ 0x4303 : u8; extern writeonly src_address_bank @ 0x4304 : u8; extern writeonly src_address_hl @ 0x4302 : u16; extern writeonly mdma_size_l @ 0x4305 : u8; extern writeonly mdma_size_h @ 0x4306 : u8; extern writeonly mdma_size_hl @ 0x4305 : u16; extern writeonly hdma_indirect_address_l @ 0x4305 : u8; extern writeonly hdma_indirect_address_h @ 0x4306 : u8; extern writeonly hdma_indirect_address_bank @ 0x4307 : u8; extern writeonly hdma_indirect_address_hl @ 0x4305 : u16; extern writeonly hdma_table_address_l @ 0x4308 : u8; extern writeonly hdma_table_address_h @ 0x4309 : u8; extern writeonly hdma_table_address_hl @ 0x4308 : u16; extern writeonly hdma_line_counter @ 0x430A : u8; } namespace dma1 { extern writeonly control @ 0x4310 : u8; extern writeonly mdma_dest @ 0x4311 : u8; extern writeonly src_address_l @ 0x4312 : u8; extern writeonly src_address_h @ 0x4313 : u8; extern writeonly src_address_bank @ 0x4314 : u8; extern writeonly src_address_hl @ 0x4312 : u16; extern writeonly mdma_size_l @ 0x4315 : u8; extern writeonly mdma_size_h @ 0x4316 : u8; extern writeonly mdma_size_hl @ 0x4315 : u16; extern writeonly hdma_indirect_address_l @ 0x4315 : u8; extern writeonly hdma_indirect_address_h @ 0x4316 : u8; extern writeonly hdma_indirect_address_bank @ 0x4317 : u8; extern writeonly hdma_indirect_address_hl @ 0x4315 : u16; extern writeonly hdma_table_address_l @ 0x4318 : u8; extern writeonly hdma_table_address_h @ 0x4319 : u8; extern writeonly hdma_table_address_hl @ 0x4318 : u16; extern writeonly hdma_line_counter @ 0x431A : u8; } namespace dma2 { extern writeonly control @ 0x4320 : u8; extern writeonly mdma_dest @ 0x4321 : u8; extern writeonly src_address_l @ 0x4322 : u8; extern writeonly src_address_h @ 0x4323 : u8; extern writeonly src_address_bank @ 0x4324 : u8; extern writeonly src_address_hl @ 0x4322 : u16; extern writeonly mdma_size_l @ 0x4325 : u8; extern writeonly mdma_size_h @ 0x4326 : u8; extern writeonly mdma_size_hl @ 0x4325 : u16; extern writeonly hdma_indirect_address_l @ 0x4325 : u8; extern writeonly hdma_indirect_address_h @ 0x4326 : u8; extern writeonly hdma_indirect_address_bank @ 0x4327 : u8; extern writeonly hdma_indirect_address_hl @ 0x4325 : u16; extern writeonly hdma_table_address_l @ 0x4328 : u8; extern writeonly hdma_table_address_h @ 0x4329 : u8; extern writeonly hdma_table_address_hl @ 0x4328 : u16; extern writeonly hdma_line_counter @ 0x432A : u8; } namespace dma3 { extern writeonly control @ 0x4330 : u8; extern writeonly mdma_dest @ 0x4331 : u8; extern writeonly src_address_l @ 0x4332 : u8; extern writeonly src_address_h @ 0x4333 : u8; extern writeonly src_address_bank @ 0x4334 : u8; extern writeonly src_address_hl @ 0x4332 : u16; extern writeonly mdma_size_l @ 0x4335 : u8; extern writeonly mdma_size_h @ 0x4336 : u8; extern writeonly mdma_size_hl @ 0x4335 : u16; extern writeonly hdma_indirect_address_l @ 0x4335 : u8; extern writeonly hdma_indirect_address_h @ 0x4336 : u8; extern writeonly hdma_indirect_address_bank @ 0x4337 : u8; extern writeonly hdma_indirect_address_hl @ 0x4335 : u16; extern writeonly hdma_table_address_l @ 0x4338 : u8; extern writeonly hdma_table_address_h @ 0x4339 : u8; extern writeonly hdma_table_address_hl @ 0x4338 : u16; extern writeonly hdma_line_counter @ 0x433A : u8; } namespace dma4 { extern writeonly control @ 0x4340 : u8; extern writeonly mdma_dest @ 0x4341 : u8; extern writeonly src_address_l @ 0x4342 : u8; extern writeonly src_address_h @ 0x4343 : u8; extern writeonly src_address_bank @ 0x4344 : u8; extern writeonly src_address_hl @ 0x4342 : u16; extern writeonly mdma_size_l @ 0x4345 : u8; extern writeonly mdma_size_h @ 0x4346 : u8; extern writeonly mdma_size_hl @ 0x4345 : u16; extern writeonly hdma_indirect_address_l @ 0x4345 : u8; extern writeonly hdma_indirect_address_h @ 0x4346 : u8; extern writeonly hdma_indirect_address_bank @ 0x4347 : u8; extern writeonly hdma_indirect_address_hl @ 0x4345 : u16; extern writeonly hdma_table_address_l @ 0x4348 : u8; extern writeonly hdma_table_address_h @ 0x4349 : u8; extern writeonly hdma_table_address_hl @ 0x4348 : u16; extern writeonly hdma_line_counter @ 0x434A : u8; } namespace dma5 { extern writeonly control @ 0x4350 : u8; extern writeonly mdma_dest @ 0x4351 : u8; extern writeonly src_address_l @ 0x4352 : u8; extern writeonly src_address_h @ 0x4353 : u8; extern writeonly src_address_bank @ 0x4354 : u8; extern writeonly src_address_hl @ 0x4352 : u16; extern writeonly mdma_size_l @ 0x4355 : u8; extern writeonly mdma_size_h @ 0x4356 : u8; extern writeonly mdma_size_hl @ 0x4355 : u16; extern writeonly hdma_indirect_address_l @ 0x4355 : u8; extern writeonly hdma_indirect_address_h @ 0x4356 : u8; extern writeonly hdma_indirect_address_bank @ 0x4357 : u8; extern writeonly hdma_indirect_address_hl @ 0x4355 : u16; extern writeonly hdma_table_address_l @ 0x4358 : u8; extern writeonly hdma_table_address_h @ 0x4359 : u8; extern writeonly hdma_table_address_hl @ 0x4358 : u16; extern writeonly hdma_line_counter @ 0x435A : u8; } namespace dma6 { extern writeonly control @ 0x4360 : u8; extern writeonly mdma_dest @ 0x4361 : u8; extern writeonly src_address_l @ 0x4362 : u8; extern writeonly src_address_h @ 0x4363 : u8; extern writeonly src_address_bank @ 0x4364 : u8; extern writeonly src_address_hl @ 0x4362 : u16; extern writeonly mdma_size_l @ 0x4365 : u8; extern writeonly mdma_size_h @ 0x4366 : u8; extern writeonly mdma_size_hl @ 0x4365 : u16; extern writeonly hdma_indirect_address_l @ 0x4365 : u8; extern writeonly hdma_indirect_address_h @ 0x4366 : u8; extern writeonly hdma_indirect_address_bank @ 0x4367 : u8; extern writeonly hdma_indirect_address_hl @ 0x4365 : u16; extern writeonly hdma_table_address_l @ 0x4368 : u8; extern writeonly hdma_table_address_h @ 0x4369 : u8; extern writeonly hdma_table_address_hl @ 0x4368 : u16; extern writeonly hdma_line_counter @ 0x436A : u8; } namespace dma7 { extern writeonly control @ 0x4370 : u8; extern writeonly mdma_dest @ 0x4371 : u8; extern writeonly src_address_l @ 0x4372 : u8; extern writeonly src_address_h @ 0x4373 : u8; extern writeonly src_address_bank @ 0x4374 : u8; extern writeonly src_address_hl @ 0x4372 : u16; extern writeonly mdma_size_l @ 0x4375 : u8; extern writeonly mdma_size_h @ 0x4376 : u8; extern writeonly mdma_size_hl @ 0x4375 : u16; extern writeonly hdma_indirect_address_l @ 0x4375 : u8; extern writeonly hdma_indirect_address_h @ 0x4376 : u8; extern writeonly hdma_indirect_address_bank @ 0x4377 : u8; extern writeonly hdma_indirect_address_hl @ 0x4375 : u16; extern writeonly hdma_table_address_l @ 0x4378 : u8; extern writeonly hdma_table_address_h @ 0x4379 : u8; extern writeonly hdma_table_address_hl @ 0x4378 : u16; extern writeonly hdma_line_counter @ 0x437A : u8; } } @@@@ <<<<<ll||88ll||88xr0 Hvx~0<60000||88080|||883333ș;~~:~:D|88::DD88UPpp PRpp >6NJ$Zl|66N~J~$qPPx~F&PP\xx>qPPÑPP\n8|p|8|><<<<,,<<~<~,~~Z @@@@< ~@@~<``~`~ B!B (  f`<<00~<<$<<~<~$~B<~~<<<<~BBB~<~<~$B~ff<~~~ffff<~<~BZ<<~~ZZZZ~~<$$~~tt>>66~~tt>>66~t>6<<B~~$<~~B<~I~~II~~H~~HJ FP98 b` y??8`<@~@| ~~A ~~~~A] <f~<<<~~~ǂm|:8s~<8DZ~&$8<8DZ~>>>>>>>>BZ3<~ZZ$A<B!<Z~<<@<Z<?BZZ<<<~ZZZ<8x0``x0800````00>>*>>**+F19$HD"dH0p80~Z ~~ZZ~BBZZBB~~~~~BBZZBB~~~~UUUUU|>66><|8||866668888B$~Z<"3~ZZ<=~灥€?>?3~~ۀ>3sZX ZZXXB@}@|????``ss77__``ss77__8M|||ZZ<< Aj;pQ0]pI#&/]0cKT,ߖ"xn9ԪC+clv&+ @f՗àwt;bcej o|_$T]r[6P[Ul QKs:Z?r-gfj %^#!.pX0ӈ|Qbb)dwfF-"%|ON}'SKLPCC/^0Q c4Vi\FG q>ETgc{D{\J*J>J71d Re>+ hۅu/suV^̣+JAtT^(YƢԯ, 8Ť>\T;-" 2MϞ;>LSꤒEwoLK>:b|!mc^hgxkagEѱYnxt9;;vUo8,ёYX[R ^?҃h}\2*} c 7>P M6cg'Nn:.DJ21dډ*q>zTlk a+npv#)^uB{| ;AT8%!| m!LغLLφ]·w5{=lNl}u+í|8e@FPDnl1KPy ˈJ) 2p,η3T/ʶj7A8:i98QNn D&&bπ8Ӓ}BNp1Y8@kkkkksIENDB`PNG  IHDR1|tIME%+ [ pHYs B4gAMA a0PLTEO&IIDATxSK,!'~z%]HP( wK7iC$6bchCF`߀l}vU ǺXL&C. qZ\]I@I6GG4rdJ{^1pf0CzL8k>V=BgP$J{i:6}c[qLxDM[be;du{x?dh$ʵ~p&=} ;ga? Zy!Ps$>Ob> 1) & 1) f.write(bytearray([c])) # Write third bits of this row. c = 0 for i in range(8): c = (c * 2) | ((data[x + i, y + j] >> 2) & 1) f.write(bytearray([c])) # Write high bits of this row. c = 0 for i in range(8): c = (c * 2) | ((data[x + i, y + j] >> 3) & 1) f.write(bytearray([c])) if __name__ == '__main__': import sys if len(sys.argv) > 1: WIDTH = 128 HEIGHT = None for arg in range(1, len(sys.argv)): filename = sys.argv[arg] if filename[0] == '-': if filename == '-oldfart': HEIGHT = 192 elif filename == '-newfart': HEIGHT = None else: exit('Invalid argument `' + filename + '`.') continue try: img = PIL.Image.open(filename) except IOError as e: if os.path.isdir(filename): exit(filename + ' is a directory.') if os.path.exists(filename): exit(filename + ' has an unsupported filetype, or you lack permission to open it.') else: exit('File ' + filename + ' does not exist!') w, h = img.size if w != WIDTH or h % 8 != 0 or HEIGHT and h != HEIGHT: exit('Image ' + filename + ' is not ' + str(WIDTH) + 'x' + str(HEIGHT) + ' pixels in size.') if not img.palette: exit('Image ' + filename + ' has no palette.') data = img.load() save_filename = os.path.splitext(filename)[0] + '.chr' try: f = open(save_filename, 'wb') except Exception as e: exit('Failure attempting to write ' + save_filename) write_chr(w, h, data, f) f.close() print(' ' + filename + ' -> ' + save_filename) else: print('Usage: ' + sys.argv[0] + ' file [file...]') print('Converts files like foo.png into Game Gear-friendly formats like foo.chr') 8888|LLLddd|888888888<<<<<||||><<<|```||||><<<>||||<<<<|lll <<<<|```|||| 8000000000000|||||||||||||||~~~~ |xxxx8888|lll||||||||||||||||~~~~~~~~~~||||||||||||||||zzzz|||||||~||||~~~~~||||||||8888||||888||||ffffffffffff~<<<<<888xppp#!/bin/env python import os import os.path import PIL.Image ''' NES: def write_chr(w, h, data, f): for y in range(0, h, 16): for x in range(0, w, 8): # Copy low bits of each 8x8 chunk into the first 8x8 plane. for j in range(8): c = 0 for i in range(8): c = (c * 2) | (data[x + i, y + j] & 1) f.write(chr(c)) # Copy high bits of each chunk into the second 8x8 plane. for j in range(8): c = 0 for i in range(8): c = (c * 2) | ((data[x + i, y + j] >> 1) & 1) f.write(chr(c)) # Copy low bits of each 8x8 chunk into the first 8x8 plane. for j in range(8): c = 0 for i in range(8): c = (c * 2) | (data[x + i, (y + 8) + j] & 1) f.write(chr(c)) # Copy high bits of each chunk into the second 8x8 plane. for j in range(8): c = 0 for i in range(8): c = (c * 2) | ((data[x + i, (y + 8) + j] >> 1) & 1) f.write(chr(c)) ''' def write_chr(w, h, data, f): for y in range(0, h, 16): for x in range(0, w, 8): for j in range(16): # Write low bits of this row. c = 0 for i in range(8): c = (c * 2) | (data[x + i, y + j] & 1) f.write(bytearray([c])) # Write second bits of this row. c = 0 for i in range(8): c = (c * 2) | ((data[x + i, y + j] >> 1) & 1) f.write(bytearray([c])) # Write third bits of this row. c = 0 for i in range(8): c = (c * 2) | ((data[x + i, y + j] >> 2) & 1) f.write(bytearray([c])) # Write high bits of this row. c = 0 for i in range(8): c = (c * 2) | ((data[x + i, y + j] >> 3) & 1) f.write(bytearray([c])) if __name__ == '__main__': import sys if len(sys.argv) > 1: WIDTH = 128 HEIGHT = None for arg in range(1, len(sys.argv)): filename = sys.argv[arg] if filename[0] == '-': if filename == '-oldfart': HEIGHT = 192 elif filename == '-newfart': HEIGHT = None else: exit('Invalid argument `' + filename + '`.') continue try: img = PIL.Image.open(filename) except IOError as e: if os.path.isdir(filename): exit(filename + ' is a directory.') if os.path.exists(filename): exit(filename + ' has an unsupported filetype, or you lack permission to open it.') else: exit('File ' + filename + ' does not exist!') w, h = img.size if w != WIDTH or h % 8 != 0 or HEIGHT and h != HEIGHT: exit('Image ' + filename + ' is not ' + str(WIDTH) + 'x' + str(HEIGHT) + ' pixels in size.') if not img.palette: exit('Image ' + filename + ' has no palette.') data = img.load() save_filename = os.path.splitext(filename)[0] + '.chr' try: f = open(save_filename, 'wb') except Exception as e: exit('Failure attempting to write ' + save_filename) write_chr(w, h, data, f) f.close() print(' ' + filename + ' -> ' + save_filename) else: print('Usage: ' + sys.argv[0] + ' file [file...]') print('Converts files like foo.png into Game Gear-friendly formats like foo.chr') @@@@ <<<<<llll||||8888xx~r00< H6v0008000|||||88883333ș;~~::~::DDD|8888UPPRpppp >666NN~JJ~$$qPPPP\xxx~F>&qPPPP\ߑn~~<<888|ppp|||888|><<<<~<<<~,,,~~Z< ~@@@@@@~<~倀```~B!B ( f`<<00~<<~<<~$$~B<<~~<<~BBB~<<~<<~$B<~~~~ffffff<~<<<~~~BZZZ~~>>>6666~t>6B~~<<$<~B<~~~~III~~~~HHJ yF?P?988 b``~<@@| ~~~~~~AA] <<<>>>>>>>>B<~ZZZ$A3<B<Z~>>>***+F91$H0pD8"dH0~~~ZZZ~ ~~~BBBBZZZZBBBB~~~~~~|UUUUU>666666><|888||888B$ہ~~ZZZ<<="3~~~灁€?>>?33s ZZZXXXB@@|}????````ssss7777____8M|||ZZZZZZ<<<<<<<<8ddffffffffffff??_???'s{، ffffffffffffffff8Ld88Ld88<8<|<`|<`|<||<|k~[2A;ثP}ٙj'EW_:F vx&+^ k5?.lt"}wRv:lCmU~q4+D-w΁"k aОmBx񎘆 NIcdO#_E9 ݙxw=:A1L- 3@s 墿xi¨KG+XWqz%AHRUe~uܯrE*(+@_^ƀE07@JqHTߣo&R;Bq[zu_2 +Qd*ܮґSzdwS 'u lBfJ ?c"\SXyg2ƛT&BU @@ 0d)|P)]<=@0?eJ 2S|&eO'0,k8W66@H߳.(`V NVȸpF*\+ b] 9Q1H{;* pq7 '}\106m𘠩{ +zgeEPRlmqbZÑy5H EɃb6<.gŒC'J'/*2>z1H(x $~])U=vy(ulLoAT" @u1$vׅk7ԉ)} ^\!X~!*2̚+LpQy L x, Lg7>{@3ON9[O JS8Q.1-s}󅴍yyM(w  Ef1ET"dIbVWWsrJᰀFG0famIE6ztH;9q!A24s(@4ٌ;;`W' HCD*# wi'pPѳ1(v†X@枂xY %*4"PĆ#$o '#Tx߇0an 20=v <3Z.9)խAY- :/<.i?pC),#+,';Puҿ*ۖIl#kf| |?փG9q2`dO ēG?LK ;;YdQkkkkkp'4byIENDB`PNG  IHDR1|0PLTE@@@"@IDATxQ C#q!$n'@hG7iڟ_E(5I 5B!2fZ̀6'"mZ/5y|WJq@3tg2(N<m17&E )OSzڟjz ,b n|8- ݣ^Y`'fW`)SC) GPzR8޿` M.\S=o4:&P> 1) & 1) f.write(chr(c)) if __name__ == '__main__': import sys def main(): if len(sys.argv) > 1: for arg in range(1, len(sys.argv)): filename = sys.argv[arg] try: img = PIL.Image.open(filename) except IOError as e: if os.path.isdir(filename): exit(filename + ' is a directory.') if os.path.exists(filename): exit(filename + ' has an unsupported filetype, or you lack permission to open it.') else: exit('File ' + filename + ' does not exist!') w, h = img.size if w != 128 or h != 128: exit('Image ' + filename + ' is not 128x128 pixels in size.') if not img.palette: exit('Image ' + filename + ' has no palette.') data = img.load() save_filename = os.path.splitext(filename)[0] + '.chr' try: f = open(save_filename, 'wb') except Exception as e: exit('Failure attempting to write ' + save_filename) write_chr(w, h, data, f) f.close() print(' ' + filename + ' -> ' + save_filename) else: print('Usage: ' + sys.argv[0] + ' file [file...]') print('Converts files like foo.png into NES-friendly formats like foo.chr') main()8Ld88Ld88<8<|<`|<`|<||<|p Z @8o)׀w .@Ko[}JzF~oz6ST"6@,^ۑWCO艁e V|־?mCahhhhhhhhhhhhhhhhhhhT kIENDB`PNG  IHDR1|,tEXtCreation TimeTue 15 Feb 2011 18:41:59 -0500tIME * XC pHYs B4gAMA a0PLTE@@@"IDATxT[ *N@H C]ݱ32!"'"m>gC ~+v%É yl{HoB}#6|AzL*ٓOJ@V JD`5A[RuB!$ @a%o50 x~W2oWp%\/(ʩ)@}u8U^ d4;>|'(nAJmgghm^<U ZDhLfݑqFcno/M\'"'|*õ asf,cA5獄( `0 `0 -5IENDB`namespace nes { namespace ppu { namespace oam { extern writeonly address @ 0x2003 : u8; extern var data @ 0x2004 : u8; extern writeonly dma @ 0x4014 : u8; let ATTRIBUTE_VFLIP = 0x80; let ATTRIBUTE_HFLIP = 0x40; let ATTRIBUTE_BEHIND = 0x20; let ATTRIBUTE_PALETTE_0 = 0x0; let ATTRIBUTE_PALETTE_1 = 0x1; let ATTRIBUTE_PALETTE_2 = 0x2; let ATTRIBUTE_PALETTE_3 = 0x3; let ATTRIBUTE_PALETTE_MASK = 0x3; let SPRITE_SIZE = 4; let SPRITE_COUNT = 64; let SPRITE_SCANLINE_LIMIT = 8; } extern writeonly control @ 0x2000 : u8; let CONTROL_NMI = 0x80; let CONTROL_OBJ_8x16 = 0x20; let CONTROL_OBJ_8x8 = 0x00; let CONTROL_BG_PATTERN_1 = 0x10; let CONTROL_BG_PATTERN_0 = 0x00; let CONTROL_OBJ_PATTERN_1 = 0x08; let CONTROL_OBJ_PATTERN_0 = 0x00; let CONTROL_VRAM_INCREMENT_32 = 0x04; let CONTROL_VRAM_INCREMENT_1 = 0x00; let CONTROL_NAMETABLE_0 = 0x00; let CONTROL_NAMETABLE_1 = 0x01; let CONTROL_NAMETABLE_2 = 0x02; let CONTROL_NAMETABLE_3 = 0x03; let CONTROL_NAMETABLE_MASK = 0x03; extern writeonly mask @ 0x2001 : u8; let MASK_INTENSIFY_B = 0x80; let MASK_INTENSIFY_G = 0x40; let MASK_INTENSIFY_R = 0x20; let MASK_RENDER_OBJ = 0x10; let MASK_RENDER_BG = 0x08; let MASK_LEFTMOST_OBJ = 0x04; let MASK_LEFTMOST_BG = 0x02; let MASK_GREYSCALE = 0x01; extern const status @ 0x2002 : u8; let STATUS_VBLANK_MASK = 0x80; let STATUS_SPRITE_ZERO_HIT_MASK = 0x40; let STATUS_SPRITE_OVERFLOW = 0x20; let STATUS_VBLANK_BIT = 7; let STATUS_SPRITE_ZERO_HIT_BIT = 6; extern writeonly scroll @ 0x2005 : u8; extern writeonly address @ 0x2006 : u8; let ADDRESS_PATTERN_DATA = 0x0000; let ADDRESS_PATTERN_0 = 0x0000; let ADDRESS_PATTERN_1 = 0x1000; let PATTERN_SIZE = 0x1000; let PATTERN_COUNT = 2; let ADDRESS_NAMETABLE_DATA = 0x2000; let ADDRESS_NAMETABLE_0 = 0x2000; let ADDRESS_NAMETABLE_1 = 0x2400; let ADDRESS_NAMETABLE_2 = 0x2800; let ADDRESS_NAMETABLE_3 = 0x2C00; let NAMETABLE_SIZE = 0x400; let NAMETABLE_COUNT = 4; let NAMETABLE_SIZE_TILE_MAP = 0x3C0; let NAMETABLE_SIZE_ATTRIBUTE_MAP = 0x40; let NAMETABLE_OFFSET_TILE_MAP = 0; let NAMETABLE_OFFSET_ATTRIBUTE_MAP = 0x3C0; let NAMETABLE_WIDTH_TILE_MAP = 32; let NAMETABLE_HEIGHT_TILE_MAP = 30; let NAMETABLE_WIDTH_ATTRIBUTE_MAP = 8; let NAMETABLE_HEIGHT_ATTRIBUTE_MAP = 8; // NOTE: row 7 only contains attributes in the top half. let ADDRESS_PALETTE_DATA = 0x3F00; let ADDRESS_PALETTE_BG_0 = 0x3F00; let ADDRESS_PALETTE_BG_1 = 0x3F04; let ADDRESS_PALETTE_BG_2 = 0x3F08; let ADDRESS_PALETTE_BG_3 = 0x3F0C; let ADDRESS_PALETTE_OBJ_0 = 0x3F10; let ADDRESS_PALETTE_OBJ_1 = 0x3F14; let ADDRESS_PALETTE_OBJ_2 = 0x3F18; let ADDRESS_PALETTE_OBJ_3 = 0x3F1C; let PALETTE_SIZE = 4; let PALETTE_COUNT = 8; let PALETTE_BG_COUNT = 4; let PALETTE_OBJ_COUNT = 4; let SCREEN_WIDTH = 256; let SCREEN_HEIGHT = 240; extern var data @ 0x2007 : u8; } namespace apu { namespace pulse { let CONTROL_DUTY_MASK = 0xC0; let CONTROL_DUTY_SHIFT = 6; let CONTROL_LENGTH_COUNTER_DISABLE = 0x20; let CONTROL_VOLUME_CONSTANT = 0x10; let CONTROL_VOLUME_ENVELOPE_MASK = 0x0F; let SWEEP_ENABLE_MASK = 0x80; let SWEEP_PERIOD_MASK = 0x70; let SWEEP_PERIOD_SHIFT = 4; let SWEEP_NEGATE = 0x08; let SWEEP_SHIFT_MASK = 0x03; let HIGH_LENGTH_MASK = 0xF8; let HIGH_LENGTH_SHIFT = 3; let HIGH_FREQUENCY_MASK = 0x03; } namespace pulse1 { extern writeonly control @ 0x4000 : u8; extern writeonly sweep @ 0x4001 : u8; extern writeonly low @ 0x4002 : u8; extern writeonly high @ 0x4003 : u8; } namespace pulse2 { extern writeonly control @ 0x4004 : u8; extern writeonly sweep @ 0x4005 : u8; extern writeonly low @ 0x4006 : u8; extern writeonly high @ 0x4007 : u8; } namespace triangle { extern writeonly control @ 0x4008 : u8; let CONTROL_LINEAR_COUNTER_ENABLE = 0x80; extern writeonly low @ 0x400A : u8; extern writeonly high @ 0x400B : u8; let HIGH_LENGTH_MASK = 0xF8; let HIGH_LENGTH_SHIFT = 3; let HIGH_FREQUENCY_MASK = 0x03; } namespace noise { extern writeonly control @ 0x400C : u8; let CONTROL_LENGTH_COUNTER_DISABLE = 0x20; let CONTROL_VOLUME_CONSTANT = 0x10; let CONTROL_VOLUME_ENVELOPE_MASK = 0x0F; extern writeonly pattern @ 0x400E : u8; let PATTERN_PERIOD_MASK = 0x0F; let PATTERN_DUTY = 0x80; extern writeonly length @ 0x400F : u8; let LENGTH_MASK = 0xF8; let LENGTH_SHIFT = 3; } namespace dmc { extern writeonly control @ 0x4010 : u8; let CONTROL_IRQ_ENABLE = 0x80; let CONTROL_LOOP = 0x40; let CONTROL_FREQUENCY_MASK = 0x0F; extern writeonly counter @ 0x4011 : u8; let COUNTER_MASK = 0x7F; extern writeonly address @ 0x4012 : u8; extern writeonly length @ 0x4013 : u8; } // Enabled channels. extern writeonly enable @ 0x4015 : u8; // DMC is enabled. let ENABLE_DMC = 0x10; // Noise is enabled let ENABLE_NOISE = 0x08; // Triangle is enabled let ENABLE_TRIANGLE = 0x04; // Pulse 2 is enabled let ENABLE_PULSE2 = 0x02; // Pulse 1 is enabled let ENABLE_PULSE1 = 0x01; // APU status register. extern const status @ 0x4015 : u8; // Mask of whether or not DMC interrupt is active. let STATUS_DMC_IRQ_MASK = 0x80; // Bit index of whether or not DMC interrupt is active. let STATUS_DMC_IRQ_BIT = 7; // Mask of whether or not frame-counter interrupt is active. let STATUS_FRAME_IRQ_MASK = 0x40; // Bit index of whether or not frame-counter interrupt is active. let STATUS_FRAME_IRQ_BIT = 6; // Mask of possible enabled channels. let STATUS_ENABLE_MASK = 0x1F; // DMC is enabled let STATUS_DMC_ENABLED = 0x10; // Noise is enabled let STATUS_NOISE_ENABLED = 0x08; // Triangle is enabled let STATUS_TRIANGLE_ENABLED = 0x04; // Pulse 2 is enabled let STATUS_PULSE2_ENABLED = 0x02; // Pulse 1 is enabled let STATUS_PULSE1_ENABLED = 0x01; // Frame counter. extern writeonly frame_counter @ 0x4017 : u8; // Disable frame-counter interrupts. let FRAME_COUNTER_IRQ_DISABLE = 0x40; // Four-step mode (faster, allows frame-counter interrupt if not disabled) let FRAME_COUNTER_FOUR_STEP = 0x00; // Five-step mode (slower) let FRAME_COUNTER_FIVE_STEP = 0x80; } namespace joy { extern writeonly output @ 0x4016 : u8; extern const input1 @ 0x4016 : u8; extern const input2 @ 0x4017 : u8; namespace bit { let A = 0; let B = 1; let SELECT = 2; let START = 3; let UP = 4; let DOWN = 5; let LEFT = 6; let RIGHT = 7; let BUTTON_START = 0; let BUTTON_COUNT = 4; let DIRECTION_START = 4; let DIRECTION_COUNT = 4; let COUNT = 8; } namespace mask { let A = 0x01; let B = 0x02; let SELECT = 0x04; let START = 0x08; let UP = 0x10; let DOWN = 0x20; let LEFT = 0x40; let RIGHT = 0x80; let BUTTONS = 0x0F; let DIRECTIONS = 0xF0; let ALL = 0xFF; } } namespace mmc1 { // The MMC1 implements its mapper interface through a 5-bit shift register. // Writing must send each bit one-by-one in the lowest bit of the port. // After the fifth bit is transferred, the data gets sent to the approriate internal register of the mapper. // For convenience, you can use the inline write macros below. // Control port (5-bit shift register). extern writeonly control @ 0x8000 : u8; // One-screen mirroring mode A (lower bank) let CONTROL_MIRROR_ONESCREEN_A = 0x00; // One-screen mirroring mode B (upper bank) let CONTROL_MIRROR_ONESCREEN_B = 0x01; // Vertical mirroring. let CONTROL_MIRROR_VERTICAL = 0x02; // Horizontal mirroring. let CONTROL_MIRROR_HORIZONTAL = 0x03; // PRG mode 0, 1: 0x8000 .. 0xFFFF - swappable 32K bank let CONTROL_PRG_MODE_32K = 0x00; // PRG mode 2: 0x8000 .. 0xBFFF - swappable 16K bank, 0xC000 .. 0xFFFF - fixed 16K bank. let CONTROL_PRG_MODE_16K_LOW_SWAP_HIGH_FIX = 0x08; // PRG mode 3: 0x8000 .. 0xBFFF - fixed 16K bank, 0xC000 .. 0xFFFF - swappable 16K bank. let CONTROL_PRG_MODE_16K_LOW_FIX_HIGH_SWAP = 0x0C; // CHR mode 0: 0x0000 .. 0x2000 - one swappable 8K bank let CONTROL_CHR_MODE_8K = 0x00; // CHR mode 0: 0x0000 .. 0x1000, 0x1000 .. 0x2000 - two swappable 4K banks let CONTROL_CHR_MODE_4K = 0x10; // Resets the shift register and resets control port to CONTROL_PRG_MODE_16K_LOW_FIX_HIGH_SWAP. let CONTROL_RESET = 0x80; // CHR bank select A (5-bit shift register). // Selects CHR bank at PPU 0x0000 .. 0x1000 (in 4K CHR mode; 5-bit index) / 0x0000 .. 0x2000 (in 8K CHR mode; 5-bit index with lowest bit ignored) extern writeonly chr_a @ 0xA000 : u8; // CHR bank select B (5-bit shift register). // Select CHR bank at PPU 0x1000 .. 0x2000 (in 4K CHR mode only; 5-bit index). extern writeonly chr_b @ 0xC000 : u8; // Mask of possible CHR bank values. let CHR_BANK_MASK = 0x0F; // PRG bank select (5-bit shift register). extern writeonly prg @ 0xE000 : u8; // Mask of possible PRG ROM bank values. let PRG_ROM_BANK_MASK = 0x0F; // Enable reading PRG RAM at 0x6000 .. 0x7FFF let PRG_RAM_ENABLE = 0x10; // Reset the MMC1 shift register to its initial state. // Modifies: a inline func reset() { control = a = CONTROL_RESET; } // Write a 5-bit value to the control register. // Arguments: a = the value to write // See: CONTROL constants inline func write_control(value : u8 in a) { inline for in 1 .. 5 { control = a; a >>>= 1; } } // Write a 5-bit value to the PRG select register. // Arguments: a = the value to write // See: PRG constants inline func write_prg(value : u8 in a) { inline for in 1 .. 5 { prg = a; a >>>= 1; } } // Write a 5-bit value to the lower CHR select register. // Arguments: a = the value to write // See: CHR constants inline func write_chr_a(value : u8 in a) { inline for in 1 .. 5 { chr_a = a; a >>>= 1; } } // Write a 5-bit value to the upper CHR select register. // Arguments: a = the value to write // See: CHR constants inline func write_chr_b(value : u8 in a) { inline for in 1 .. 5 { chr_b = a; a >>>= 1; } } } namespace mmc3 { namespace irq { // This register specifies the IRQ counter reload value. // When the IRQ counter is zero (or a reload is requested through 0xC001), // this value will be copied into the MMC3 IRQ counter at // the end of the current scanline extern writeonly latch @ 0xC000 : u8; // Writing any value to this register clears the MMC3 IRQ counter // so that it will be reloaded at the end of the current scanline. extern writeonly reload @ 0xC001 : u8; // Writing any value to this register will disable MMC3 interrupts // AND acknowledge any pending interrupts. extern writeonly disable @ 0xE000 : u8; // Writing any value to this register will enable MMC3 interrupts. extern writeonly enable @ 0xE001 : u8; } // Bank select register. extern writeonly select @ 0x8000 : u8; // Select 2K CHR bank A at PPU 0x0000 .. 0x07FF (CHR mode 0) / 0x1000 .. 0x17FF (CHR mode 1) let SELECT_2K_CHR_BANK_A = 0x00; // Select 2K CHR bank B at PPU 0x0800 .. 0x0FFF (CHR mode 0) / 0x1800 .. 0x1FFF (CHR mode 1) let SELECT_2K_CHR_BANK_B = 0x01; // Select 1K CHR bank A at PPU 0x1000 .. 0x13FF (CHR mode 0) / 0x0000 .. 0x03FF (CHR mode 1) let SELECT_1K_CHR_BANK_A = 0x02; // Select 1K CHR bank B at PPU 0x1400 .. 0x17FF (CHR mode 0) / 0x0400 .. 0x07FF (CHR mode 1) let SELECT_1K_CHR_BANK_B = 0x03; // Select 1K CHR bank C at PPU 0x1800 .. 0x1BFF (CHR mode 0) / 0x0800 .. 0x0BFF (CHR mode 1) let SELECT_1K_CHR_BANK_C = 0x04; // Select 1K CHR bank D at PPU 0x1C00 .. 0x1FFF (CHR mode 0) / 0x0C00 .. 0x0FFF (CHR mode 1) let SELECT_1K_CHR_BANK_D = 0x05; // Select 8K CHR bank A at CPU 0x8000 .. 0x9FFF (PRG mode 0) / 0xC000 .. 0xDFFF (PRG mode 1) let SELECT_8K_PRG_BANK_A = 0x06; // Select 8K CHR bank B at CPU 0xA000 .. 0xBFFF let SELECT_8K_PRG_BANK_B = 0x07; // PRG mode 0: 0x8000 .. 0x9FFF - swappable, 0xC000 .. 0xDFFF - fixed to second-last bank. let SELECT_PRG_MODE_0 = 0x00; // PRG mode 1: 0xC000 .. 0xDFFF - swappable, 0x8000 .. 0x9FFF - fixed to second-last bank. let SELECT_PRG_MODE_1 = 0x40; // CHR mode 0: 0x0000 .. 0x0FFF - two 2K banks, 0x1000 .. 0x1FFF - four 1K banks. let SELECT_CHR_MODE_0 = 0x00; // CHR mode 1: 0x0000 .. 0x0FFF - four 1K banks, 0x1000 .. 0x1FFF - two 2K banks. let SELECT_CHR_MODE_1 = 0x80; // Bank value to write, based on last value written to bank select register. extern writeonly data @ 0x8001 : u8; // Nametable mirroring setting. extern writeonly mirror @ 0xA000 : u8; // Vertical mirroring. let MIRROR_VERTICAL = 0x0; // Horizontal mirroring. let MIRROR_HORIZONTAL = 0x1; // Controls access to the WRAM. extern writeonly prg_ram_control @ 0xA001 : u8; // Disable writing RAM at 0x6000 .. 0x7FFF let PRG_RAM_CONTROL_DISABLE_WRITE = 0x40; // Enable reading RAM at 0x6000 .. 0x7FFF let PRG_RAM_CONTROL_ENABLE = 0x80; } namespace mmc6 { namespace irq { // This register specifies the IRQ counter reload value. // When the IRQ counter is zero (or a reload is requested through 0xC001), // this value will be copied into the MMC3 IRQ counter at // the end of the current scanline extern writeonly latch @ 0xC000 : u8; // Writing any value to this register clears the MMC3 IRQ counter // so that it will be reloaded at the end of the current scanline. extern writeonly reload @ 0xC001 : u8; // Writing any value to this register will disable MMC3 interrupts // AND acknowledge any pending interrupts. extern writeonly disable @ 0xE000 : u8; // Writing any value to this register will enable MMC3 interrupts. extern writeonly enable @ 0xE001 : u8; } extern writeonly select @ 0x8000 : u8; // Select 2K CHR bank A at PPU 0x0000 .. 0x07FF (CHR mode 0) / 0x1000 .. 0x17FF (CHR mode 1) let SELECT_2K_CHR_BANK_A = 0x00; // Select 2K CHR bank B at PPU 0x0800 .. 0x0FFF (CHR mode 0) / 0x1800 .. 0x1FFF (CHR mode 1) let SELECT_2K_CHR_BANK_B = 0x01; // Select 1K CHR bank A at PPU 0x1000 .. 0x13FF (CHR mode 0) / 0x0000 .. 0x03FF (CHR mode 1) let SELECT_1K_CHR_BANK_A = 0x02; // Select 1K CHR bank B at PPU 0x1400 .. 0x17FF (CHR mode 0) / 0x0400 .. 0x07FF (CHR mode 1) let SELECT_1K_CHR_BANK_B = 0x03; // Select 1K CHR bank C at PPU 0x1800 .. 0x1BFF (CHR mode 0) / 0x0800 .. 0x0BFF (CHR mode 1) let SELECT_1K_CHR_BANK_C = 0x04; // Select 1K CHR bank D at PPU 0x1C00 .. 0x1FFF (CHR mode 0) / 0x0C00 .. 0x0FFF (CHR mode 1) let SELECT_1K_CHR_BANK_D = 0x05; // Select 8K CHR bank A at CPU 0x8000 .. 0x9FFF (PRG mode 0) / 0xC000 .. 0xDFFF (PRG mode 1) let SELECT_8K_PRG_BANK_A = 0x06; // Select 8K CHR bank B at CPU 0xA000 .. 0xBFFF let SELECT_8K_PRG_BANK_B = 0x07; // Enable PRG RAM. let SELECT_PRG_RAM_ENABLE = 0x20; // PRG mode 0: 0x8000 .. 0x9FFF - swappable, 0xC000 .. 0xDFFF - fixed to second-last bank. let SELECT_PRG_MODE_0 = 0x00; // PRG mode 1: 0xC000 .. 0xDFFF - swappable, 0x8000 .. 0x9FFF - fixed to second-last bank. let SELECT_PRG_MODE_1 = 0x40; // CHR mode 0: 0x0000 .. 0x0FFF - two 2K banks, 0x1000 .. 0x1FFF - four 1K banks. let SELECT_CHR_MODE_0 = 0x00; // CHR mode 1: 0x0000 .. 0x0FFF - four 1K banks, 0x1000 .. 0x1FFF - two 2K banks. let SELECT_CHR_MODE_1 = 0x80; // New bank value, based on last value written to bank select register extern writeonly data @ 0x8001 : u8; // Nametable mirroring setting. extern writeonly mirror @ 0xA000 : u8; let MIRROR_VERTICAL = 0x0; let MIRROR_HORIZONTAL = 0x1; // Controls access to the WRAM. extern writeonly prg_ram_control @ 0xA001 : u8; // Enable writing RAM at 0x7000 .. 0x71FF. (Must enable read bit too if writing.) let PRG_RAM_CONTROL_ENABLE_WRITE_L = 0x10; // Enable reading RAM at 0x7000 .. 0x71FF. let PRG_RAM_CONTROL_ENABLE_READ_L = 0x20; // Enable writing RAM at 0x7100 .. 0x72FF. (Must enable read bit too if writing.) let PRG_RAM_CONTROL_ENABLE_WRITE_H = 0x40; // Enable reading RAM at 0x7100 .. 0x72FF. let PRG_RAM_CONTROL_ENABLE_READ_H = 0x80; } }x|6~~<~lۇv~vÅ~BB~BBBZN~<$$<~~^^^~>q~F&\x>q\nO~~<3f~Z||><<,<~~~~Z @@<~~<`~Û~ B!B(  f`<<00~罽~~~B~~~BBB~~~$B<~~ff<~BZ<~ZZZZ~~<$$~t>6~t>6~t>6<>>BZ3<~ZZ$A>*+F19$HD"dH0p80 ~Z~BZB~~~~BZB~~~UUUUU|>><|||6688B$~"3~Z=??~۽s ZXB}|??`s7_`s7_8M|||ZZ<< 1: WIDTH = 128 HEIGHT = None for arg in range(1, len(sys.argv)): filename = sys.argv[arg] if filename[0] == '-': if filename == '-oldfart': HEIGHT = 192 elif filename == '-newfart': HEIGHT = None else: exit('Invalid argument `' + filename + '`.') continue try: img = PIL.Image.open(filename) except IOError as e: if os.path.isdir(filename): exit(filename + ' is a directory.') if os.path.exists(filename): exit(filename + ' has an unsupported filetype, or you lack permission to open it.') else: exit('File ' + filename + ' does not exist!') w, h = img.size if w != WIDTH or h % 8 != 0 or HEIGHT and h != HEIGHT: exit('Image ' + filename + ' is not ' + str(WIDTH) + 'x' + str(HEIGHT) + ' pixels in size.') if not img.palette: exit('Image ' + filename + ' has no palette.') data = img.load() save_filename = os.path.splitext(filename)[0] + '.chr' try: f = open(save_filename, 'wb') except Exception as e: exit('Failure attempting to write ' + save_filename) write_chr(w, h, data, f) f.close() print(' ' + filename + ' -> ' + save_filename) else: print('Usage: ' + sys.argv[0] + ' file [file...]') print('Converts files like foo.png into MSX1-friendly formats like foo.chr') PNG  IHDR1|tIME7~ pHYs B4gAMA a0PLTEO&I@IDATxQ CsKn 4ϯc$ !TRlf@@6c\+?^:[J ^O'?EЂaw"҅Tqا)_v_5 XGD=tfny>lQ__,b3«V)KH!#(w)k\S\0Å_&~iqp)u7yFl(' )"N^v |=B'!aZ<`Gg5>cko$ B!B!{w. IENDB`8Ld88<|<`|<| 1: WIDTH = 128 HEIGHT = None for arg in range(1, len(sys.argv)): filename = sys.argv[arg] if filename[0] == '-': if filename == '-oldfart': HEIGHT = 192 elif filename == '-newfart': HEIGHT = None else: exit('Invalid argument `' + filename + '`.') continue try: img = PIL.Image.open(filename) except IOError as e: if os.path.isdir(filename): exit(filename + ' is a directory.') if os.path.exists(filename): exit(filename + ' has an unsupported filetype, or you lack permission to open it.') else: exit('File ' + filename + ' does not exist!') w, h = img.size if w != WIDTH or h % 8 != 0 or HEIGHT and h != HEIGHT: exit('Image ' + filename + ' is not ' + str(WIDTH) + 'x' + str(HEIGHT) + ' pixels in size.') if not img.palette: exit('Image ' + filename + ' has no palette.') data = img.load() save_filename = os.path.splitext(filename)[0] + '.chr' try: f = open(save_filename, 'wb') except Exception as e: exit('Failure attempting to write ' + save_filename) write_chr(w, h, data, f) f.close() print(' ' + filename + ' -> ' + save_filename) else: print('Usage: ' + sys.argv[0] + ' file [file...]') print('Converts files like foo.png into MSX1-friendly formats like foo.chr') // TODO: add lots of missing I/O register definitions, clean up definitions. // TODO: variables in I/O space? instead of io_write/io_read, just use like a register/variable. namespace msx { namespace bios { namespace rst { // TODO: make defines for all the functions listed here: http://map.grauw.nl/resources/msxbios.php } } namespace konami { extern writeonly rom_6000 @ 0x6000 : u8; extern writeonly rom_8000 @ 0x8000 : u8; extern writeonly rom_A000 @ 0xA000 : u8; } namespace scc { extern writeonly control @ 0x9000 : u8; let CONTROL_ENABLE = 0x3F; let CONTROL_DISALBE = 0x00; extern var wave_0 @ 0x9800 : [u8; 32]; extern var wave_1 @ 0x9820 : [u8; 32]; extern var wave_2 @ 0x9840 : [u8; 32]; extern var wave_34 @ 0x9860 : [u8; 32]; extern var frequency_l_0 @ 0x9880 : u8; extern var frequency_h_0 @ 0x9881 : u8; extern var frequency_l_1 @ 0x9882 : u8; extern var frequency_h_1 @ 0x9883 : u8; extern var frequency_l_2 @ 0x9884 : u8; extern var frequency_h_2 @ 0x9885 : u8; extern var frequency_l_3 @ 0x9886 : u8; extern var frequency_h_3 @ 0x9887 : u8; extern var frequency_l_4 @ 0x9888 : u8; extern var frequency_h_4 @ 0x9889 : u8; extern var volume_0 @ 0x988A : u8; extern var volume_1 @ 0x988B : u8; extern var volume_2 @ 0x988C : u8; extern var volume_3 @ 0x988D : u8; extern var volume_4 @ 0x988E : u8; extern var channel_enable @ 0x988F : u8; let CHANNEL_ENABLE_4 = 0x10; let CHANNEL_ENABLE_3 = 0x08; let CHANNEL_ENABLE_2 = 0x04; let CHANNEL_ENABLE_1 = 0x02; let CHANNEL_ENABLE_0 = 0x01; } namespace ascii8 { extern writeonly rom_4000 @ 0x4000 : u8; extern writeonly rom_6000 @ 0x6000 : u8; extern writeonly rom_8000 @ 0x8000 : u8; extern writeonly rom_A000 @ 0xA000 : u8; } namespace ascii16 { extern writeonly rom_4000 @ 0x4000 : u8; extern writeonly rom_8000 @ 0x8000 : u8; } namespace io { namespace vdp { let data = 0x98; let control = 0x99; // Writing to the control port lets you access one of the following through the data port. let CONTROL_ACCESS_REGISTER = 0x80; let CONTROL_ACCESS_VRAM_READ = 0x00; let CONTROL_ACCESS_VRAM_WRITE = 0x40; // Reading the control port gives back VDP status. let CONTROL_STATUS_BIT_VBLANK = 7; let CONTROL_STATUS_BIT_SPRITE_OVERFLOW = 6; let CONTROL_STATUS_BIT_SPRITE_COLLISION = 5; let CONTROL_STATUS_MASK_VBLANK = 0x80; let CONTROL_STATUS_MASK_SPRITE_OVERFLOW = 0x40; let CONTROL_STATUS_MASK_SPRITE_COLLISION = 0x20; let CONTROL_STATUS_MASK_FIFTH_SPRITE = 0x1F; } namespace vdp2 { let palette = 0x9A; let register_data = 0x9B; } namespace memory { let control = 0x3E; let CONTROL_EXPANSION_DISABLE = 0x80; let CONTROL_CARTRIDGE_DISABLE = 0x40; let CONTROL_CARD_DISABLE = 0x20; let CONTROL_RAM_DISABLE = 0x10; let CONTROL_BIOS_DISABLE = 0x04; let CONTROL_DEVICE_DISABLE = 0x02; } namespace ppi { let primary_slot = 0xA8; let PRIMARY_SLOT_0000_MASK = 0x03; let PRIMARY_SLOT_4000_MASK = 0x0C; let PRIMARY_SLOT_8000_MASK = 0x30; let PRIMARY_SLOT_C000_MASK = 0xC0; let PRIMARY_SLOT_MAIN_ROM = 0; let PRIMARY_SLOT_CART_A = 0; let PRIMARY_SLOT_CART_B = 0; let PRIMARY_SLOT_AUX = 0; let keyboard_status = 0xA9; let select = 0xAA; let SELECT_KEYBOARD_CLICK = 0x80; let SELECT_CAPSLOCK_LED = 0x40; let SELECT_CASSETTE_AUDIO_OUT = 0x20; let SELECT_CASSETTE_MOTOR_ON = 0x10; let SELECT_KEYBOARD_LINE_MASK = 0x0F; let control = 0xAB; let CONTROL_BIT_INDEX_MASK = 0x0E; let CONTROL_BIT_INDEX_SHIFT = 1; let CONTROL_BIT_SET = 0x01; let CONTROL_BIT_RESET = 0x00; } namespace psg { let index = 0xA0; let write = 0xA1; let read = 0xA2; } namespace rtc { let index = 0xB4; let data = 0xB5; } namespace acia { let data = 0x80; let control = 0x81; let CONTROL_STATUS_DATA_SET_READY = 0x80; let CONTROL_STATUS_SYNC_BREAK = 0x40; let CONTROL_STATUS_FRAMING_ERROR = 0x20; let CONTROL_STATUS_OVERRUN_ERROR = 0x10; let CONTROL_STATUS_PARITY_ERROR = 0x08; let CONTROL_STATUS_TRANSMIT_EMPTY = 0x04; let CONTROL_STATUS_RECEIVE_READY = 0x02; let CONTROL_STATUS_TRANSMIT_READY = 0x01; let CONTROL_MODE_STOP_2_BIT = 0xC0; let CONTROL_MODE_STOP_1_5_BIT = 0x80; let CONTROL_MODE_STOP_1_BIT = 0x40; let CONTROL_MODE_STOP_INVALID = 0x00; let CONTROL_MODE_PARITY_CHECK = 0x20; let CONTROL_MODE_ENABLE_PARITY = 0x10; let CONTROL_MODE_WORD_8_BIT = 0x0C; let CONTROL_MODE_WORD_7_BIT = 0x08; let CONTROL_MODE_WORD_6_BIT = 0x04; let CONTROL_MODE_WORD_5_BIT = 0x00; let CONTROL_MODE_BAUD_28_8_KHZ = 0x03; let CONTROL_MODE_BAUD_115_2_KHZ = 0x02; let CONTROL_MODE_BAUD_1843_2_KHZ = 0x01; let CONTROL_MODE_BAUD_SYNC = 0x00; let CONTROL_COMMAND_HUNT_MODE = 0x80; let CONTROL_COMMAND_INTERNAL_RESET = 0x40; let CONTROL_COMMAND_SEND_REQUEST = 0x20; let CONTROL_COMMAND_CLEAR_ERRORS = 0x10; let CONTROL_COMMAND_BREAK = 0x08; let CONTROL_COMMAND_RECEIVE = 0x04; let CONTROL_COMMAND_DATA_TERMINAL_READY = 0x02; let CONTROL_COMMAND_TRANSMIT = 0x01; } let system_enable = 0xF5; let SYSTEM_ENABLE_CLOCK_ID = 0x80; let SYSTEM_ENABLE_LIGHTPEN = 0x40; let SYSTEM_ENABLE_RS232C = 0x20; let SYSTEM_ENABLE_MSX_INTERFACE = 0x10; let SYSTEM_ENABLE_SUPERIMPOSE = 0x08; let SYSTEM_ENABLE_MSX_AUDIO = 0x04; let SYSTEM_ENABLE_KANJI_2 = 0x02; let SYSTEM_ENABLE_KANJI_1 = 0x01; let av_control = 0xF7; let AV_CONTROL_REVERSE_VDP_BIT_5 = 0x80; let AV_CONTROL_REVERSE_VDP_BIT_4 = 0x40; let AV_CONTROL_YM_CONTROL = 0x20; let AV_CONTROL_AV_CONTROL = 0x10; let AV_CONTROL_ENABLE_RGB21_INPUT = 0x04; let AV_CONTROL_L = 0x02; let AV_CONTROL_R = 0x01; let AV_CONTROL_STATUS_RGB21_INPUT_ENABLED = 0x08; } // VDP registers namespace vdp { namespace color { let TRANSPARENT = 0; let BLACK = 1; let MEDIUM_GREEN = 2; let LIGHT_GREEN = 3; let DARK_BLUE = 4; let LIGHT_BLUE = 5; let DARK_RED = 6; let CYAN = 7; let MEDIUM_RED = 8; let LIGHT_RED = 9; let DARK_YELLOW = 10; let LIGHT_YELLOW = 11; let DARK_GREEN = 12; let MAGENTA = 13; let GRAY = 14; let WHITE = 15; } let mode_control_0 = 0x00; let MODE_CONTROL_0_DIGITIZE = 0x40; let MODE_CONTROL_0_LIGHTPEN_MOUSE = 0x20; let MODE_CONTROL_0_HBLANK_IRQ = 0x10; let MODE_CONTROL_0_M5 = 0x08; let MODE_CONTROL_0_M4 = 0x04; let MODE_CONTROL_0_M3 = 0x02; let MODE_CONTROL_0_EXTERNAL_INPUT = 0x01; let mode_control_1 = 0x01; let MODE_CONTROL_1_ENABLE = 0x40; let MODE_CONTROL_1_VBLANK_IRQ = 0x20; let MODE_CONTROL_1_M1 = 0x10; let MODE_CONTROL_1_M2 = 0x08; let MODE_CONTROL_1_SPRITE_16x16 = 0x02; let MODE_CONTROL_1_SPRITE_8x8 = 0x00; let MODE_CONTROL_1_SPRITE_STRETCH = 0x01; let nametable_address = 0x02; let NAMETABLE_ADDRESS_SHIFT = 10; let colortable_address = 0x03; let COLORTABLE_ADDRESS_SHIFT = 6; let tile_pattern_address = 0x04; let TILE_PATTERN_ADDRESS_SHIFT = 11; let sprite_attribute_address = 0x05; let SPRITE_ATTRIBUTE_ADDRESS_SHIFT = 7; let sprite_pattern_address = 0x06; let SPRITE_PATTERN_ADDRESS_SHIFT = 7; let overscan_color = 0x07; } // VDP registers (MSX2 only) namespace vdp2 { let mode_control_2 = 0x08; let MODE_CONTROL_2_MOUSE_SELECT = 0x80; let MODE_CONTROL_2_LIGHTPEN_SELECT = 0x40; let MODE_CONTROL_2_OPAQUE_COLOR0 = 0x20; let MODE_CONTROL_2_COLOR_BUS_INPUT = 0x10; let MODE_CONTROL_2_VRAM_SIZE_FAST_64K = 0x0C; let MODE_CONTROL_2_VRAM_SIZE_64K = 0x08; let MODE_CONTROL_2_VRAM_SIZE_4X_16K = 0x04; let MODE_CONTROL_2_VRAM_SIZE_1X_16K = 0x00; let MODE_CONTROL_2_DISABLE_OBJ = 0x02; let MODE_CONTROL_2_GREYSCALE = 0x01; let mode_control_3 = 0x09; let MODE_CONTROL_3_SCREEN_HEIGHT_212 = 0x80; let MODE_CONTROL_3_SCREEN_HEIGHT_192 = 0x00; let MODE_CONTROL_3_SIMULTANEOUS_EXTERN = 0x20; let MODE_CONTROL_3_SIMULTANEOUS_MIX = 0x10; let MODE_CONTROL_3_SIMULTANEOUS_INTERN = 0x00; let MODE_CONTROL_3_INTERLACE = 0x08; let MODE_CONTROL_3_EVEN_ODD = 0x04; let MODE_CONTROL_3_NTSC = 0x02; let MODE_CONTROL_3_DOT_CLOCK_INPUT = 0x01; let colortable_address_h = 0x0A; let sprite_attribute_address_h = 0x0B; let blink_color = 0x0C; let blink_period = 0x0D; let vram_bank_select = 0x0E; let status_register_index = 0x0F; let palette_index = 0x10; let register_index = 0x11; let REGISTER_INDEX_DISABLE_AUTO_INCREMENT = 0x80; let display_adjust = 0x12; let DISPLAY_ADJUST_X_MASK = 0x0F; let DISPLAY_ADJUST_Y_MASK = 0xF0; let DISPLAY_ADJUST_Y_SHIFT = 8; let scanline_interrupt_line = 0x13; let vscroll = 0x17; let hscroll_control = 0x19; let HSCROLL_CONTROL_COMMAND_ALTERNATE = 0x80; let HSCROLL_CONTROL_COMMAND_NORMAL = 0x00; let HSCROLL_CONTROL_PIN8_VDS = 0x20; let HSCROLL_CONTROL_PIN8_CPU_CLOCK = 0x00; let HSCROLL_CONTROL_ENABLE_YJK_ATTRIBUTES = 0x10; let HSCROLL_CONTROL_ENABLE_YJK = 0x08; let HSCROLL_CONTROL_ENABLE_WAITSTATE = 0x04; let HSCROLL_CONTROL_HIDE_LEFTMOST = 0x02; let HSCROLL_CONTROL_TWO_PAGE = 0x01; let hscroll_offset_h = 0x1A; let hscroll_offset_l = 0x1B; let source_x_l = 0x20; let source_x_h = 0x21; let source_y_l = 0x22; let source_y_h = 0x23; let dest_x_l = 0x24; let dest_x_h = 0x25; let dest_y_l = 0x26; let dest_y_h = 0x27; let width_l = 0x28; let width_h = 0x29; let height_l = 0x2A; let height_h = 0x2B; let data = 0x2C; let argument = 0x2D; let command = 0x2E; } namespace psg { let frequency_l_a = 0x00; let frequency_h_a = 0x01; let frequency_l_b = 0x02; let frequency_h_b = 0x03; let frequency_l_c = 0x04; let frequency_h_c = 0x05; let noise_period = 0x06; let mixer = 0x07; let MIXER_IO_PORT_B_OUTPUT = 0x80; let MIXER_IO_PORT_A_OUTPUT = 0x40; let MIXER_ENABLE_NOISE_C = 0x20; let MIXER_ENABLE_NOISE_B = 0x10; let MIXER_ENABLE_NOISE_A = 0x08; let MIXER_ENABLE_TONE_C = 0x04; let MIXER_ENABLE_TONE_B = 0x02; let MIXER_ENABLE_TONE_A = 0x01; let volume_a = 0x08; let volume_b = 0x09; let volume_c = 0x0A; let envelope_frequency_l = 0x0B; let envelope_frequency_h = 0x0C; let envelope_shape = 0x0D; let ENVELOPE_SHAPE_CONTINUE = 0x08; let ENVELOPE_SHAPE_ATTACK = 0x04; let ENVELOPE_SHAPE_ALTERNATE = 0x02; let ENVELOPE_SHAPE_HOLD = 0x01; let io_port_a = 0x0E; let IO_PORT_A_CASSETTE = 0x80; let IO_PORT_A_KEYBOARD_SWITCH = 0x40; let IO_PORT_A_JOY_B = 0x20; let IO_PORT_A_JOY_A = 0x10; let IO_PORT_A_JOY_RIGHT = 0x08; let IO_PORT_A_JOY_LEFT = 0x04; let IO_PORT_A_JOY_DOWN = 0x02; let IO_PORT_A_JOY_UP = 0x01; let io_port_b = 0x0F; let IO_PORT_B_LED = 0x80; let IO_PORT_B_JOY_INDEX = 0x40; let IO_PORT_B_PULSE_2 = 0x20; let IO_PORT_B_PULSE_1 = 0x10; let IO_PORT_B_TOUCHPAD_HANDSHAKE = 0x0F; } namespace rtc { let mode = 0x0D; let test = 0x0E; let reset = 0x0F; } namespace ppi { // Read is inverted from write. extern var secondary_slot @ 0xFFFF : u8; let SECONDARY_SLOT_0000_MASK = 0x03; let SECONDARY_SLOT_4000_MASK = 0x0C; let SECONDARY_SLOT_8000_MASK = 0x30; let SECONDARY_SLOT_C000_MASK = 0xC0; let SECONDARY_SLOT_AUX_SUB_DISK = 1; let SECONDARY_SLOT_AUX_RAM = 2; } namespace ram { extern var bank_0000 @ 0xFC : u8; extern var bank_4000 @ 0xFD : u8; extern var bank_8000 @ 0xFE : u8; extern var bank_C000 @ 0xFF : u8; } } namespace pce { namespace vce { // Control register. extern writeonly control @ 0x0400 : u8; let CONTROL_PIXEL_CLOCK_5MHz = 0x00; let CONTROL_PIXEL_CLOCK_7MHz = 0x01; let CONTROL_PIXEL_CLOCK_10MHz = 0x03; let CONTROL_PIXEL_CLOCK_MASK = 0x03; let CONTROL_FIELD_EXTRA_LINE = 0x04; let CONTROL_STRIP_GREYSCALE = 0x80; // Address registers. extern writeonly address_l @ 0x0402 : u8; extern writeonly address_h @ 0x0403 : u8; // Data registers. // Stored in a weird BRG333 format. extern var data_l @ 0x0404 : u8; extern var data_h @ 0x0405 : u8; // Mask of possible blue color channel values. let DATA_BLUE_MASK = 0x007; // Starting bit of blue color channel. let DATA_BLUE_SHIFT = 0; // Mask of possible red color channel values. let DATA_RED_MASK = 0x038; // Starting bit of red color channel. let DATA_RED_SHIFT = 3; // Mask of possible green color channel values. let DATA_GREEN_MASK = 0x1C0; // Starting bit of green color channel. let DATA_GREEN_SHIFT = 6; } namespace vdc { // VDC status. extern const status @ 0x0000 : u8; let STATUS_BUSY_MASK = 0x40; let STATUS_VBLANK = 0x20; let STATUS_VRAM_DMA_END = 0x10; let STATUS_SATB_DMA_END = 0x08; let STATUS_SCANLINE = 0x04; let STATUS_OVERFLOW = 0x02; let STATUS_COLLISION = 0x01; let STATUS_BUSY_BIT = 6; // VDC port select. extern writeonly select @ 0x0000 : u8; let SELECT_VRAM_WRITE_ADDRESS = 0x00; let SELECT_VRAM_READ_ADDRESS = 0x01; let SELECT_VRAM_DATA = 0x02; let SELECT_CONTROL = 0x05; let SELECT_SCANLINE_COMPARE = 0x06; let SELECT_SCROLL_X = 0x07; let SELECT_SCROLL_Y = 0x08; let SELECT_MEMORY_SIZE = 0x09; let SELECT_HSYNC_SETTING = 0x0A; let SELECT_HDISP_SETTING = 0x0B; let SELECT_VSYNC_SETTING = 0x0C; let SELECT_VDISP_HEIGHT = 0x0D; let SELECT_VDISP_END = 0x0E; let SELECT_DMA_CONTROL = 0x0F; let SELECT_DMA_SOURCE = 0x10; let SELECT_DMA_DEST = 0x11; let SELECT_DMA_LEN = 0x12; let SELECT_SATB_SOURCE_ADDRESS = 0x13; // Data registers. extern var data_l @ 0x0002 : u8; extern var data_h @ 0x0003 : u8; // Tilemap (also known as the Block Attribute Table / BAT) always starts at 0x0000. // Size occupied is defined by tilemap memory size setting. let DATA_VRAM_ADDRESS_TILEMAP = 0x0000; let TILEMAP_INDEX_MASK = 0x0FFF; let TILEMAP_ATTRIBUTE_MASK = 0xF000; let DATA_H_CONTROL_INCREMENT_MASK = 0x18; let DATA_H_CONTROL_INCREMENT_128 = 0x18; let DATA_H_CONTROL_INCREMENT_64 = 0x10; let DATA_H_CONTROL_INCREMENT_32 = 0x08; let DATA_H_CONTROL_INCREMENT_1 = 0x00; let DATA_L_CONTROL_ENABLE_BG = 0x80; let DATA_L_CONTROL_ENABLE_SPRITES = 0x40; let DATA_L_CONTROL_ENABLE_VBLANK_IRQ = 0x08; let DATA_L_CONTROL_ENABLE_HBLANK_IRQ = 0x04; let DATA_L_CONTROL_ENABLE_SPRITE_OVERFLOW_IRQ = 0x02; let DATA_L_CONTROL_ENABLE_SPRITE_ZERO_HIT_IRQ = 0x01; let DATA_SCROLL_MASK = 0x1FF; let DATA_L_MEMORY_SIZE_VRAM_PIXEL_WIDTH_MASK = 0x03; let DATA_L_MEMORY_SIZE_VRAM_SPRITE_WIDTH_MASK = 0x0C; let DATA_L_MEMORY_SIZE_VRAM_SPRITE_WIDTH_SHIFT = 2; let DATA_L_MEMORY_SIZE_TILEMAP_32x32 = 0x00; let DATA_L_MEMORY_SIZE_TILEMAP_64x32 = 0x10; let DATA_L_MEMORY_SIZE_TILEMAP_128x32 = 0x20; let DATA_L_MEMORY_SIZE_TILEMAP_32x64 = 0x40; let DATA_L_MEMORY_SIZE_TILEMAP_64x64 = 0x50; let DATA_L_MEMORY_SIZE_TILEMAP_128x64 = 0x60; let DATA_L_MEMORY_SIZE_TILEMAP_MASK = 0x70; let DATA_L_MEMORY_SIZE_TILEMAP_SHIFT = 4; let DATA_L_HSYNC_SETTING_SYNC_WIDTH_MASK = 0x1F; let DATA_H_HSYNC_SETTING_DISPLAY_START_MASK = 0x7F; let DATA_L_HDISP_SETTING_DISPLAY_WIDTH_MASK = 0x7F; let DATA_H_HDISP_SETTING_DISPLAY_END_MASK = 0x7F; let DATA_L_VSYNC_SYNC_HEIGHT_MASK = 0x1F; let DATA_H_VSYNC_DISPLAY_START_MASK = 0xFF; let DATA_VDISP_HEIGHT_MASK = 0x1FF; let DATA_VDISP_END_MASK = 0x1FF; let DATA_L_DMA_CONTROL_ENABLE_SATB_DMA_END_IRQ = 0x01; let DATA_L_DMA_CONTROL_ENABLE_VRAM_DMA_END_IRQ = 0x02; let DATA_L_DMA_CONTROL_SOURCE_INCREMENT = 0x00; let DATA_L_DMA_CONTROL_SOURCE_DECREMENT = 0x04; let DATA_L_DMA_CONTROL_DEST_INCREMENT = 0x00; let DATA_L_DMA_CONTROL_DEST_DECREMENT = 0x08; let DATA_L_DMA_CONTROL_SATB_AUTO_TRANSFER = 0x10; let SATB_Y_MASK = 0x3FF; let SATB_X_MASK = 0x3FF; // sprite data VRAM address shifted right 5 bits (Shift left 6 bits to get real VRAM address) let SATB_VRAM_ADDRESS_MASK = 0x3FF; // sprite attributes let SATB_ATTRIBUTE_H_VFLIP = 0x80; let SATB_ATTRIBUTE_H_HEIGHT_16 = 0x00; let SATB_ATTRIBUTE_H_HEIGHT_32 = 0x10; let SATB_ATTRIBUTE_H_HEIGHT_64 = 0x30; let SATB_ATTRIBUTE_H_HEIGHT_MASK = 0x30; let SATB_ATTRIBUTE_H_HFLIP = 0x0800; let SATB_ATTRIBUTE_H_WIDTH_16 = 0x00; let SATB_ATTRIBUTE_H_WIDTH_32 = 0x01; let SATB_ATTRIBUTE_L_BG_PRIORITY = 0x80; let SATB_ATTRIBUTE_L_PALETTE_INDEX_MASK = 0x0F; let SATB_OFFSET_Y = 0x00; let SATB_OFFSET_X = 0x01; let SATB_OFFSET_VRAM_ADDRESS = 0x01; let SATB_OFFSET_ATTRIBUTE = 0x01; } namespace irq { // Controls which interrupts are disabled. extern var disable @ 0x1402 : u8; // Pending interrupts. extern const status @ 0x1403 : u8; // Write here to acknowledge a timer interrupt. extern writeonly acknowledge @ 0x1403 : u8; // Timer interrupts. let INTERRUPT_TIMER = 0x04; // VDC-generated interrupts. let INTERRUPT_VDC = 0x02; // External interrupts. (cartridge, super-CD, user-requested) let INTERRUPT_EXTERNAL = 0x01; // Mask of all interrupts. let INTERRUPT_ALL = 0x07; } namespace timer { // Current timer value. extern const value @ 0x0C00 : u8; // Mask of possible timer values. let VALUE_MASK = 0x7F; // Timer reload value. extern writeonly reload @ 0x0C00 : u8; // Mask of possible timer reload values. let RELOAD_MASK = 0x7F; // Timer control register. extern writeonly control @ 0x0C01 : u8; // Enable the timer. let CONTROL_ENABLE = 0x01; } namespace io { // Input port. extern const input @ 0x1000 : u8; // Mask for CDROM connection (0 = attached, 1 = detached) let INPUT_CD_MASK = 0x80; // Mask for country code. (0 = Japan, 1 = US) let INPUT_COUNTRY_MASK = 0x40; // Mask of possible values for button reading. let INPUT_VALUE_MASK = 0x0F; // Bit for CDROM connection (0 = attached, 1 = detached) let INPUT_CD_BIT = 7; // Bit for country code. (0 = Japan, 1 = US) let INPUT_COUNTRY_BIT = 6; // Output port. extern writeonly output @ 0x1000 : u8; // Clear pin. let OUTPUT_CLEAR = 0x02; // Select pin. let OUTPUT_SELECT = 0x01; namespace joy { // Select buttons. let SELECT_BUTTONS = 0x00; // Select directionals. let SELECT_DIRECTIONS = 0x01; // I button status. let BUTTON_I = 0x01; // II button status let BUTTON_II = 0x02; // Select button status. let BUTTON_SELECT = 0x04; // Start button status. let BUTTON_RUN = 0x08; // Mask of all possible buttons. let BUTTON_MASK = 0x0F; // Up direction status. let DIRECTION_UP = 0x01; // Right direction status. let DIRECTION_RIGHT = 0x02; // Down direction status. let DIRECTION_DOWN = 0x04; // Left direction status. let DIRECTION_LEFT = 0x08; // Mask of all possible directions. let DIRECTION_MASK = 0x0F; // III button status for 6-button controller. let BUTTON_6B_III = 0x01; // IV button status for 6-button controller. let BUTTON_6B_IV = 0x02; // V button status for 6-button controller. let BUTTON_6B_V = 0x04; // VI button status for 6-button controller. let BUTTON_6B_VI = 0x08; } } namespace psg { // http://www.magicengine.com/mkit/doc_hard_psg.html namespace channel_data { // 12-bit frequency low bits (bits 0 .. 7) extern writeonly frequency_l @ 0x0802 : u8; // 12-bit frequency high bits (bits 8 .. 11) extern writeonly frequency_h @ 0x0803 : u8; // Mask of possible values that are used for high bits of frequency. let FREQUENCY_H_MASK = 0x0F; // Control register extern writeonly control @ 0x0804 : u8; // Enable wave output. let CONTROL_ENABLE_WAVE = 0x80; // Enable direct output. let CONTROL_ENABLE_DIRECT = 0xC0; // Wave index is reset to beginning. let CONTROL_RESET_WAVE_INDEX = 0x40; // Mask of possible values that can be used for gain. let CONTROL_GAIN_MASK = 0x1F; // Volume register. extern writeonly volume @ 0x0805 : u8; // Mask of possible values that can be used for left volume. let VOLUME_LEFT_MASK = 0xF0; // Mask of possible values that can be used for right volume. let VOLUME_RIGHT_MASK = 0x0F; // Wave data register. Writes a single sample into the 32-sample wave buffer of the channel at the current index. extern writeonly wave @ 0x0806 : u8; // Mask of possible values that can be used for wave sample data. let WAVE_DATA_MASK = 0x1F; // (Channels 4 .. 5) Noise register. extern writeonly noise @ 0x0807 : u8; // Enable noise on this channel. let NOISE_ENABLE = 0x80; // Mask of possible values that can be used for noise frequency. let NOISE_FREQUENCY_MASK = 0x1F; } // Current channel to write data for. extern writeonly channel_index @ 0x0800 : u8; // Number of channels available on the PSG. let CHANNEL_COUNT = 6; // Master volume. extern writeonly volume @ 0x0801 : u8; // Mask of possible values that can be used for left volume. let VOLUME_LEFT_MASK = 0xF0; // Mask of possible values that can be used for right volume. let VOLUME_RIGHT_MASK = 0x0F; namespace lfo { // LFO frequency register. Multiplied against channel 1's 12-bit frequency to get the effective frequency of the LFO. extern writeonly frequency @ 0x0808 : u8; // LFO control register. extern writeonly control @ 0x0809 : u8; // Enable LFO modulation mode (channel 1 is used to control an LFO that gets applied to channel 0) let CONTROL_ENABLE = 0x80; // Add LFO sample x 0 to channel 0 (no modulation) let CONTROL_LFO_SAMPLE_MULTIPLIER_0 = 0x00; // Add LFO sample x 1 to channel 0 let CONTROL_LFO_SAMPLE_MULTIPLIER_1 = 0x01; // Add LFO sample x 16 to channel 0 let CONTROL_LFO_SAMPLE_MULTIPLIER_16 = 0x02; // Add LFO sample x 256 to channel 0 let CONTROL_LFO_SAMPLE_MULTIPLIER_256 = 0x03; // Mask of possible values that can be used for the LFO sample multiplier. let CONTROL_LFO_SAMPLE_MULTIPLIER_MASK = 0x03; } } namespace syscard { // Add address definition for Backup RAM // Add address definition for Work RAM // Add entry points to call System Card BIOS ROM } namespace cdrom { // Add entry points to call Super CD-ROM2 BIOS } // TODO: Memory Base 128 routines. // https://forums.nesdev.com/viewtopic.php?f=5&t=13082&hilit=memory+base+128 // http://pcedev.blockos.org/viewtopic.php?f=5&t=98 }PNG  IHDR1|,tEXtCreation TimeTue 15 Feb 2011 18:41:59 -0500tIME$T pHYs B4gAMA a0PLTE#I, pVZIDATxVb xcWaƯ'7ilˆm ~W DjuVU("> Aj;pQ0]pI#&/]0cKT,ߖ"xn9ԪC+clv&+ @f՗àwt;bcej o|_$T]r[6P[Ul QKs:Z?r-gfj %^#!.pX0ӈ|Qbb)dwfF-"%|ON}'SKLPCC/^0Q c4Vi\FG q>ETgc{D{\J*J>J71d Re>+ hۅu/suV^̣+JAtT^(YƢԯ, 8Ť>\T;-" 2MϞ;>LSꤒEwoLK>:b|!mc^hgxkagEѱYnxt9;;vUo8,ёYX[R ^?҃h}\2*} c 7>P M6cg'Nn:.DJ21dډ*q>zTlk a+npv#)^uB{| ;AT8%!| m!LغLLφ]·w5{=lNl}u+í|8e@FPDnl1KPy ˈJ) 2p,η3T/ʶj7A8:i98QNn D&&bπ8Ӓ}BNp1Y8@kkkkksIENDB`PNG  IHDR1|tIME%+ [ pHYs B4gAMA a0PLTEO&IIDATxSK,!'~z%]HP( wK7iC$6bchCF`߀l}vU ǺXL&C. qZ\]I@I6GG4rdJ{^1pf0CzL8k>V=BgP$J{i:6}c[qLxDM[be;du{x?dh$ʵ~p&=} ;ga? Zy!Ps$>Ob<|`||<<``||><>||||<<||<<|l <> 1) & 1) f.write(bytearray([c])) for j in range(8): # Write third bits of this row. c = 0 for i in range(8): c = (c * 2) | ((data[x + i, y + j] >> 2) & 1) f.write(bytearray([c])) # Write high bits of this row. c = 0 for i in range(8): c = (c * 2) | ((data[x + i, y + j] >> 3) & 1) f.write(bytearray([c])) if __name__ == '__main__': import sys if len(sys.argv) > 1: WIDTH = 128 HEIGHT = None for arg in range(1, len(sys.argv)): filename = sys.argv[arg] if filename[0] == '-': if filename == '-oldfart': HEIGHT = 192 elif filename == '-newfart': HEIGHT = None else: exit('Invalid argument `' + filename + '`.') continue try: img = PIL.Image.open(filename) except IOError as e: if os.path.isdir(filename): exit(filename + ' is a directory.') if os.path.exists(filename): exit(filename + ' has an unsupported filetype, or you lack permission to open it.') else: exit('File ' + filename + ' does not exist!') w, h = img.size if w != WIDTH or h % 8 != 0 or HEIGHT and h != HEIGHT: exit('Image ' + filename + ' is not ' + str(WIDTH) + 'x' + str(HEIGHT) + ' pixels in size.') if not img.palette: exit('Image ' + filename + ' has no palette.') data = img.load() save_filename = os.path.splitext(filename)[0] + '.chr' try: f = open(save_filename, 'wb') except Exception as e: exit('Failure attempting to write ' + save_filename) write_chr(w, h, data, f) f.close() print(' ' + filename + ' -> ' + save_filename) else: print('Usage: ' + sys.argv[0] + ' file [file...]') print('Converts files like foo.png into Game Gear-friendly formats like foo.chr') @@@@ <<<<<ll||88ll||88xr0 Hvx~0<60000||88080|||883333ș;~~:~:D|88::DD88UPpp PRpp >6NJ$Zl|66N~J~$qPPx~F&PP\xx>qPPÑPP\n8|p|8|><<<<,,<<~<~,~~Z @@@@< ~@@~<``~`~ B!B (  f`<<00~<<$<<~<~$~B<~~<<<<~BBB~<~<~$B~ff<~~~ffff<~<~BZ<<~~ZZZZ~~<$$~~tt>>66~~tt>>66~t>6<<B~~$<~~B<~I~~II~~H~~HJ FP98 b` y??8`<@~@| ~~A ~~~~A] <f~<<<~~~ǂm|:8s~<8DZ~&$8<8DZ~>>>>>>>>BZ3<~ZZ$A<B!<Z~<<@<Z<?BZZ<<<~ZZZ<8x0``x0800````00>>*>>**+F19$HD"dH0p80~Z ~~ZZ~BBZZBB~~~~~BBZZBB~~~~UUUUU|>66><|8||866668888B$~Z<"3~ZZ<=~灥€?>?3~~ۀ>3sZX ZZXXB@}@|????``ss77__``ss77__8M|||ZZ<<>>= 1; if !carry { a = 0x20; } gb.joy.ctrl = a; gb.joy.ctrl = a = 0x30; e--; } while !zero; b--; } while !zero; gb.joy.ctrl = a = 0x20; gb.joy.ctrl = a = 0x30; bc = 6400; do { nop(); nop(); nop(); bc--; a = c | b; } while !zero; } // Send multiple 16-byte SGB-formatted packets in a row. // // Arguments: hl = pointer to a sequence of 16-byte packets, terminated by a single 0xFF byte. #[fallthrough] func send_packet_sequence(sequence_ptr : *u8 in hl) { while true { a = *(hl as *u8); return if a == 0xFF; send_packet(sequence_ptr); } } // Detects if running on the Super Game Boy. // After: sgb_detected = 1 if found, 0 otherwise. func detect() { // Turn on 2P mode. send_packet(&packet_2_player_mode[0]); // If joystick id != 0 in the next two reads, we successfully switched to multiplayer mode (which means we're on a Super Game Boy) joy.read_raw(); goto was_detected if a != 0; joy.read_raw(); goto was_detected if a != 0; was_not_detected: a = 0; goto done_detection; was_detected: a = 1; done_detection: sgb_detected = a; // Turn off 1P mode. send_packet(&packet_1_player_mode[0]); } const packet_1_player_mode : [u8] = [gb.super.MLT_REQ | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; const packet_2_player_mode : [u8] = [gb.super.MLT_REQ | 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // Prepares the screen so that a VRAM transfer can be completed. func prepare_vram_transfer_offscreen() { if { a = gb.lcd.ctrl; } && a $ gb.lcd.CTRL_BIT_ENABLE { do { a = gb.scanline.current; } while a != 144; } gb.lcd.ctrl = a = 0; gb.scroll.x = a = 0; gb.scroll.y = a; gb.mono.palette.bg = a = 0b11100100; hl = &gb.ram.map as u16; de = 12; a = 0; b = 18; do { c = 20; do { *(hl++ as *u8) = a; a++; c--; } while !zero; hl += de; b--; } while !zero; gb.lcd.ctrl = a = gb.lcd.CTRL_ON | gb.lcd.CTRL_TILESET2 | gb.lcd.CTRL_BG_ON; } }// Fills a range in memory with a specified byte value. // // Notes: // - Some memory is unsafe to write while other hardware is using it. // - This will not work for 0xFExx addressses. Use the OAM library instead for modifying OAM memory. // // Arguments: // // hl = destination address // a = value // bc = byte count // // After: hl += bc, bc = 0, a is preserved. func memset(dest : *u8 in hl, value : u8 in a, count : u16 in bc) { memset_inline(dest, value, count); } inline func memset_inline(dest : *u8 in hl, value : u8 in a, count : u16 in bc) { ++<:count; ++>:count; goto start; repeat: *dest++ = value; start: --<:count; goto repeat if !zero; -->:count; goto repeat if !zero; } // Copies count bytes from source to destination. // // Notes: // - Some memory is unsafe to write to while other hardware is using it. // - This will not work for 0xFExx addressses. Use the OAM library instead for modifying OAM memory. // // Arguments: // // de = destination address // hl = source address // bc = byte count // // After: de += bc, hl += bc, bc = 0 func memcpy(dest : *u8 in de, source : *u8 in hl, count : u16 in bc) { memcpy_inline(dest, source, count); } inline func memcpy_inline(dest : *u8 in de, source : *u8 in hl, count : u16 in bc) { ++<:count; ++>:count; goto start; repeat: *dest++ = a = *source++; start: --<:count; goto repeat if !zero; -->:count; goto repeat if !zero; }import "gb"; import "banks"; namespace gbc_util { in hram { var gbc_detected : u8; var gba_detected : u8; } // Must be called near the very start of the program (relies on startup state of a and b registers) // After: // gbc_detected = 1 if running on GBC-compatible hardware, 0 otherwise. // gba_detected = 1 if running on a GBA, 0 otherwise. func detect() { if a == 0x11 { gba_detected = a = b & 1; gbc_detected = a = 1; } else { a = 0; gba_detected = a; gbc_detected = a; } } // Arguments: b = desired speed setting (gb.color.SPEED_MASK_TURBO_ON or gb.color.SPEED_MASK_TURBO_OFF) func set_speed(desired_speed : u8 in b) { if { a = gbc_detected; } && a != 0 { if { a = gb.color.speed & b; } && a != b { gb.joy.ctrl = a = 0x30; gb.color.speed = a = gb.color.SPEED_MASK_SWITCH; stop(); } } } }namespace vcs { namespace sync { var vsync @ 0x00 : u8; let VSYNC_START = 0x02; var vblank @ 0x01 : u8; let VBLANK_START = 0x02; let VBLANK_RESET_TRIGGER = 0x40; let VBLANK_RESET_POTS = 0x80; var wsync @ 0x02 : u8; var rsync @ 0x03 : u8; } namespace audio { var volumes @ 0x19 : [u8; 2]; var volume1 @ 0x19 : u8; var volume2 @ 0x1A : u8; var frequencies @ 0x17 : [u8; 2]; var frequency1 @ 0x17 : u8; var frequency2 @ 0x18 : u8; var tones @ 0x15 : [u8; 2]; var tone1 @ 0x15 : u8; var tone2 @ 0x16 : u8; } namespace io { var pots @ 0x3C : [u8; 4]; var pot1 @ 0x38 : u8; var pot2 @ 0x39 : u8; var pot3 @ 0x3A : u8; var pot4 @ 0x3B : u8; var triggers @ 0x3C : [u8; 2]; var trigger1 @ 0x3C : u8; var trigger2 @ 0x3D : u8; let TRIGGER_JOY_FIRE = 0x80; var port_a @ 0x280 : u8; var port_b @ 0x282 : u8; var ddr_a @ 0x281 : u8; var ddr_b @ 0x023 : u8; let PORT_A_JOY_UP = 0x10; let PORT_A_JOY_DOWN = 0x20; let PORT_A_JOY_LEFT = 0x40; let PORT_A_JOY_RIGHT = 0x80; let PORT_A_JOY2_UP = 0x01; let PORT_A_JOY2_DOWN = 0x02; let PORT_A_JOY2_LEFT = 0x04; let PORT_A_JOY2_RIGHT = 0x08; } namespace timer { var value @ 0x284 : u8; var stat @ 0x285 : u8; var set1 @ 0x294 : u8; var set8 @ 0x295 : u8; var set64 @ 0x296 : u8; var set1024 @ 0x297 : u8; } namespace control { var players @ 0x04 : [u8; 2]; var player1 @ 0x04 : u8; var player2 @ 0x05 : u8; let PLAYER_SINGLE = 0x00; let PLAYER_SINGLE_2X = 0x05; let PLAYER_SINGLE_4X = 0x07; let PLAYER_DOUBLE_CLOSE = 0x01; let PLAYER_DOUBLE_MEDIUM = 0x02; let PLAYER_DOUBLE_FAR = 0x04; let PLAYER_TRIPLE_CLOSE = 0x03; let PLAYER_TRIPLE_MEDIUM = 0x06; let MISSILE_1PX = 0x00; let MISSILE_2PX = 0x10; let MISSILE_4PX = 0x20; let MISSILE_8PX = 0x30; var playfield @ 0x0A : u8; let FIELD_REFLECT = 0x1; let FIELD_SCORE = 0x2; let FIELD_PRIORITY = 0x4; let BALL_1PX = 0x00; let BALL_2PX = 0x10; let BALL_4PX = 0x20; let BALL_8PX = 0x30; } namespace color { var players @ 0x06 : [u8; 2]; var player1 @ 0x06 : u8; var player2 @ 0x07 : u8; var fg @ 0x08 : u8; var bg @ 0x09 : u8; let LUMINOSITY_SHIFT = 1; let LUMINOSITY_MASK = 0x0E; let COLOR_SHIFT = 4; let COLOR_MASK = 0xF0; let SECAM_BLACK = 0x0; let SECAM_BLUE = 0x2; let SECAM_RED = 0x4; let SECAM_MAGENTA = 0x6; let SECAM_GREEN = 0x8; let SECAM_CYAN = 0xA; let SECAM_YELLOW = 0xC; let SECAM_WHITE = 0xE; let PAL_GREY = 0x0; let PAL_YELLOW = 0x2; let PAL_OLIVE = 0x3; let PAL_BROWN = 0x4; let PAL_GREEN = 0x5; let PAL_RED = 0x6; let PAL_CYAN = 0x7; let PAL_MAGENTA = 0x8; let PAL_LIGHT_BLUE = 0x9; let PAL_PURPLE = 0xA; let PAL_SKY_BLUE = 0xB; let PAL_INDIGO = 0xC; let PAL_BLUE = 0xD; let NTSC_WHITE = 0x0; let NTSC_YELLOW = 0x1; let NTSC_ORANGE = 0x2; let NTSC_RED_ORANGE = 0x3; let NTSC_RED = 0x4; let NTSC_MAGENTA = 0x5; let NTSC_PURPLE = 0x6; let NTSC_BLUE_PURPLE = 0x7; let NTSC_BLUE = 0x8; let NTSC_SKY_BLUE = 0x9; let NTSC_CYAN = 0xA; let NTSC_MINT = 0xB; let NTSC_GREEN = 0xC; let NTSC_GREEN_YELLOW = 0xD; let NTSC_OLIVE = 0xE; let NTSC_BROWN = 0xF; } namespace pattern { var players @ 0x1B : [u8; 2]; var player1 @ 0x1B : u8; var player2 @ 0x1C : u8; var missiles @ 0x1D : [u8; 2]; var missile1 @ 0x1D : u8; var missile2 @ 0x1E : u8; let MISSILE_FILL = 0x2; var ball @ 0x1F : u8; let BALL_FILL = 0x2; var playfields @ 0x0D : [u8; 3]; var playfield1 @ 0x0D : u8; var playfield2 @ 0x0E : u8; var playfield3 @ 0x0F : u8; } namespace hmove { var players @ 0x20 : [u8; 2]; var player1 @ 0x20 : u8; var player2 @ 0x21 : u8; var missiles @ 0x22 : [u8; 2]; var missile1 @ 0x22 : u8; var missile2 @ 0x23 : u8; var ball @ 0x24 : u8; var apply @ 0x2A : u8; var clear @ 0x2B : u8; } namespace vdelay { var players @ 0x25 : [u8; 2]; var player1 @ 0x25 : u8; var player2 @ 0x26 : u8; var ball @ 0x27 : u8; } namespace reflect { var players @ 0x0B : [u8; 2]; var player1 @ 0x0B : u8; var player2 @ 0x0C : u8; let ENABLE = 0x08; } namespace warp { var missiles @ 0x28 : [u8; 2]; var missile1 @ 0x28 : u8; var missile2 @ 0x29 : u8; let ENABLE = 0x02; } namespace reset { var players @ 0x10 : [u8; 2]; var player1 @ 0x10 : u8; var player2 @ 0x11 : u8; var missiles @ 0x12 : [u8; 2]; var missile1 @ 0x12 : u8; var missile2 @ 0x13 : u8; var ball @ 0x14 : u8; } namespace collision { var clear @ 0x2C : u8; var missile1_vs_players @ 0x30 : u8; var missile2_vs_players @ 0x31 : u8; var player1_vs_playfield @ 0x32 : u8; var player2_vs_playfield @ 0x33 : u8; var missile1_vs_playfield @ 0x34 : u8; var missile2_vs_playfield @ 0x35 : u8; var ball_vs_field @ 0x36 : u8; var pvp_mvm @ 0x37 : u8; } }namespace spc { extern writeonly control @ 0xF1 : u8; let CONTROL_PORT_23_CLEAR_MASK = 0x20; let CONTROL_PORT_01_CLEAR_MASK = 0x10; let CONTROL_TIMER_2_ENABLE_MASK = 0x04; let CONTROL_TIMER_1_ENABLE_MASK = 0x02; let CONTROL_TIMER_0_ENABLE_MASK = 0x01; let CONTROL_PORT_23_CLEAR_BIT = 5; let CONTROL_PORT_01_CLEAR_BIT = 4; let CONTROL_TIMER_2_ENABLE_BIT = 2; let CONTROL_TIMER_1_ENABLE_BIT = 1; let CONTROL_TIMER_0_ENABLE_BIT = 0; namespace dsp { extern var address @ 0xF2 : u8; let ADDRESS_VOLUME_L_0 = 0x00; let ADDRESS_VOLUME_L_1 = 0x10; let ADDRESS_VOLUME_L_2 = 0x20; let ADDRESS_VOLUME_L_3 = 0x30; let ADDRESS_VOLUME_L_4 = 0x40; let ADDRESS_VOLUME_L_5 = 0x50; let ADDRESS_VOLUME_L_6 = 0x60; let ADDRESS_VOLUME_L_7 = 0x70; let ADDRESS_VOLUME_R_0 = 0x01; let ADDRESS_VOLUME_R_1 = 0x11; let ADDRESS_VOLUME_R_2 = 0x21; let ADDRESS_VOLUME_R_3 = 0x31; let ADDRESS_VOLUME_R_4 = 0x41; let ADDRESS_VOLUME_R_5 = 0x51; let ADDRESS_VOLUME_R_6 = 0x61; let ADDRESS_VOLUME_R_7 = 0x71; let ADDRESS_PITCH_L_0 = 0x02; let ADDRESS_PITCH_L_1 = 0x12; let ADDRESS_PITCH_L_2 = 0x22; let ADDRESS_PITCH_L_3 = 0x32; let ADDRESS_PITCH_L_4 = 0x42; let ADDRESS_PITCH_L_5 = 0x52; let ADDRESS_PITCH_L_6 = 0x62; let ADDRESS_PITCH_L_7 = 0x72; let ADDRESS_PITCH_H_0 = 0x03; let ADDRESS_PITCH_H_1 = 0x13; let ADDRESS_PITCH_H_2 = 0x23; let ADDRESS_PITCH_H_3 = 0x33; let ADDRESS_PITCH_H_4 = 0x43; let ADDRESS_PITCH_H_5 = 0x53; let ADDRESS_PITCH_H_6 = 0x63; let ADDRESS_PITCH_H_7 = 0x73; let ADDRESS_SOURCE_0 = 0x04; let ADDRESS_SOURCE_1 = 0x14; let ADDRESS_SOURCE_2 = 0x24; let ADDRESS_SOURCE_3 = 0x34; let ADDRESS_SOURCE_4 = 0x44; let ADDRESS_SOURCE_5 = 0x54; let ADDRESS_SOURCE_6 = 0x64; let ADDRESS_SOURCE_7 = 0x74; let ADDRESS_ADSR_L_0 = 0x05; let ADDRESS_ADSR_L_1 = 0x15; let ADDRESS_ADSR_L_2 = 0x25; let ADDRESS_ADSR_L_3 = 0x35; let ADDRESS_ADSR_L_4 = 0x45; let ADDRESS_ADSR_L_5 = 0x55; let ADDRESS_ADSR_L_6 = 0x65; let ADDRESS_ADSR_L_7 = 0x75; let ADDRESS_ADSR_H_0 = 0x06; let ADDRESS_ADSR_H_1 = 0x16; let ADDRESS_ADSR_H_2 = 0x26; let ADDRESS_ADSR_H_3 = 0x36; let ADDRESS_ADSR_H_4 = 0x46; let ADDRESS_ADSR_H_5 = 0x56; let ADDRESS_ADSR_H_6 = 0x66; let ADDRESS_ADSR_H_7 = 0x76; let ADDRESS_GAIN_0 = 0x07; let ADDRESS_GAIN_1 = 0x17; let ADDRESS_GAIN_2 = 0x27; let ADDRESS_GAIN_3 = 0x37; let ADDRESS_GAIN_4 = 0x47; let ADDRESS_GAIN_5 = 0x57; let ADDRESS_GAIN_6 = 0x67; let ADDRESS_GAIN_7 = 0x77; let ADDRESS_ENV_0 = 0x08; let ADDRESS_ENV_1 = 0x18; let ADDRESS_ENV_2 = 0x28; let ADDRESS_ENV_3 = 0x38; let ADDRESS_ENV_4 = 0x48; let ADDRESS_ENV_5 = 0x58; let ADDRESS_ENV_6 = 0x68; let ADDRESS_ENV_7 = 0x78; let ADDRESS_OUT_0 = 0x09; let ADDRESS_OUT_1 = 0x19; let ADDRESS_OUT_2 = 0x29; let ADDRESS_OUT_3 = 0x39; let ADDRESS_OUT_4 = 0x49; let ADDRESS_OUT_5 = 0x59; let ADDRESS_OUT_6 = 0x69; let ADDRESS_OUT_7 = 0x79; let ADDRESS_MAIN_VOLUME_L = 0x0C; let ADDRESS_MAIN_VOLUME_R = 0x1C; let ADDRESS_ECHO_VOLUME_L = 0x2C; let ADDRESS_ECHO_VOLUME_R = 0x3C; let ADDRESS_KEY_ON = 0x4C; let ADDRESS_KEY_OFF = 0x5C; let ADDRESS_FLAGS = 0x6C; let ADDRESS_END_STATUS = 0x7C; let ADDRESS_ECHO_FEEDBACK = 0x0D; let ADDRESS_PITCH_MODULATION_ENABLE = 0x2D; let ADDRESS_NOISE_ENABLE = 0x3D; let ADDRESS_ECHO_ENABLE = 0x4D; let ADDRESS_SOURCE_DIRECTORY_PAGE = 0x5D; let ADDRESS_ECHO_BUFFER_PAGE = 0x6D; let ADDRESS_ECHO_DELAY = 0x7D; let ADDRESS_FIR_COEFFICIENT_0 = 0x0F; let ADDRESS_FIR_COEFFICIENT_1 = 0x1F; let ADDRESS_FIR_COEFFICIENT_2 = 0x2F; let ADDRESS_FIR_COEFFICIENT_3 = 0x3F; let ADDRESS_FIR_COEFFICIENT_4 = 0x4F; let ADDRESS_FIR_COEFFICIENT_5 = 0x5F; let ADDRESS_FIR_COEFFICIENT_6 = 0x6F; let ADDRESS_FIR_COEFFICIENT_7 = 0x7F; extern var data @ 0xF3 : u8; let CHANNEL_MASK_0 = 0b00000001; let CHANNEL_MASK_1 = 0b00000010; let CHANNEL_MASK_2 = 0b00000100; let CHANNEL_MASK_3 = 0b00001000; let CHANNEL_MASK_4 = 0b00010000; let CHANNEL_MASK_5 = 0b00100000; let CHANNEL_MASK_6 = 0b01000000; let CHANNEL_MASK_7 = 0b10000000; let DATA_ADSR_L_ATTACK_MASK = 0x0F; let DATA_ADSR_L_DECAY_MASK = 0x70; let DATA_ADSR_L_DECAY_SHIFT = 4; let DATA_ADSR_L_ENABLE = 0x80; let DATA_ADSR_H_SUSTAIN_MASK = 0x1F; let DATA_ADSR_H_RELEASE_MASK = 0xE0; let DATA_ADSR_H_RELEASE_SHIFT = 5; let DATA_GAIN_CONSTANT = 0x00; let DATA_GAIN_CONSTANT_VALUE_MASK = 0x3F; let DATA_GAIN_FADE_SPEED_MASK = 0x1F; let DATA_GAIN_FADE_LINEAR_IN = 0xC0; let DATA_GAIN_FADE_BENT_IN = 0xE0; let DATA_GAIN_FADE_LINEAR_OUT = 0x80; let DATA_GAIN_FADE_EXPONENTIAL_OUT = 0xE0; let DATA_ENV_MASK = 0x7F; let DATA_FLAGS_RESET = 0x80; let DATA_FLAGS_MUTE = 0x40; let DATA_FLAGS_ECHO_DISABLE = 0x20; let DATA_FLAGS_NOISE_CLOCK_MASK = 0x1F; let DATA_ECHO_DELAY_MASK = 0x0F; extern var data_and_address @ 0xF2 : u16; } namespace port { extern writeonly output0 @ 0xF4 : u8; extern writeonly output1 @ 0xF5 : u8; extern writeonly output2 @ 0xF6 : u8; extern writeonly output3 @ 0xF7 : u8; extern writeonly output10 @ 0xF4 : u16; extern writeonly output21 @ 0xF5 : u16; extern writeonly output32 @ 0xF6 : u16; extern const input0 @ 0xF4 : u8; extern const input1 @ 0xF5 : u8; extern const input2 @ 0xF6 : u8; extern const input3 @ 0xF7 : u8; extern const input10 @ 0xF4 : u16; extern const input21 @ 0xF5 : u16; extern const input32 @ 0xF6 : u16; } namespace timer { extern writeonly delay0 @ 0xFA : u8; extern writeonly delay1 @ 0xFB : u8; extern writeonly delay2 @ 0xFC : u8; extern const counter0 @ 0xFD : u8; extern const counter1 @ 0xFE : u8; extern const counter2 @ 0xFF : u8; let COUNTER_VALUE_MASK = 0xF; } }