Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Z80 Assembler -> Hex Opcode

by Elgon (Curate)
on Feb 08, 2003 at 14:49 UTC ( #233706=CUFP: print w/ replies, xml ) Need Help??

After going through a phase of recent nostalgia, coupled with some boredom, I decided that it would be a fun idea to write a Z80 assembler in Perl. There are other reasons for this, as my father is building a telescope, the controller of which runs via a Z80 microprocessor. Plus some day I might get around to resurrecting the small Z80-based computer I built when I was 15 and this would be useful.

Anyway, I digress: The actual instruction program isn't very big, but the hash containing the opcodes is a tad large at 694 lines, there being 694 instructions in the (documented) instruction set. There is a discussion of various issues at the bottom.

#!/usr/bin/perl -w use strict; # Set up big hash of hashes of hashes containing # our instructions and opcodes. my %opcodes = ('nop' => {'null' => {'null' => '00'}}, 'rlca' => {'null' => {'null' => '07'}}, 'rrca' => {'null' => {'null' => '0f'}}, 'rla' => {'null' => {'null' => '17'}}, 'rra' => {'null' => {'null' => '1f'}}, 'daa' => {'null' => {'null' => '27'}}, 'cpl' => {'null' => {'null' => '2f'}}, 'scf' => {'null' => {'null' => '37'}}, 'ccf' => {'null' => {'null' => '3f'}}, 'halt' => {'null' => {'null' => '76'}}, 'exx' => {'null' => {'null' => 'd9'}}, 'di' => {'null' => {'null' => 'f3'}}, 'ei' => {'null' => {'null' => 'fb'}}, 'neg' => {'null' => {'null' => 'ed 44'}}, 'retn' => {'null' => {'null' => 'ed 45'}}, 'reti' => {'null' => {'null' => 'ed 4d'}}, 'rrd' => {'null' => {'null' => 'ed 67'}}, 'rld' => {'null' => {'null' => 'ed 6f'}}, 'ldi' => {'null' => {'null' => 'ed a0'}}, 'cpi' => {'null' => {'null' => 'ed a1'}}, 'ini' => {'null' => {'null' => 'ed a2'}}, 'outi' => {'null' => {'null' => 'ed a3'}}, 'ldd' => {'null' => {'null' => 'ed a8'}}, 'cpd' => {'null' => {'null' => 'ed a9'}}, 'ind' => {'null' => {'null' => 'ed aa'}}, 'outd' => {'null' => {'null' => 'ed ab'}}, 'ldir' => {'null' => {'null' => 'ed bo'}}, 'cpir' => {'null' => {'null' => 'ed b1'}}, 'inir' => {'null' => {'null' => 'ed b2'}}, 'otir' => {'null' => {'null' => 'ed b3'}}, 'lddr' => {'null' => {'null' => 'ed b8'}}, 'cpdr' => {'null' => {'null' => 'ed b9'}}, 'indr' => {'null' => {'null' => 'ed ba'}}, 'otdr' => {'null' => {'null' => 'ed bb'}}, 'inc' => {'bc' => {'null' => '03'}, 'b' => {'null' => '04'}, 'c' => {'null' => '0c'}, 'de' => {'null' => '13'}, 'd' => {'null' => '14'}, 'e' => {'null' => '1c'}, 'hl' => {'null' => '23'}, 'h' => {'null' => '24'}, 'l' => {'null' => '2c'}, 'sp' => {'null' => '33'}, '(hl)' => {'null' => '34'}, 'a' => {'null' => '3c'}, 'ix' => {'null' => 'dd 23'}, 'iy' => {'null' => 'fd 23'}, 'ixpo' => {'null' => 'dd 34'}, 'iypo' => {'null' => 'fd 34'}}, 'dec' => {'b' => {'null' => '05'}, 'bc' => {'null' => '0b'}, 'c' => {'null' => '0d'}, 'd' => {'null' => '15'}, 'de' => {'null' => '1b'}, 'e' => {'null' => '1d'}, 'h' => {'null' => '25'}, 'hl' => {'null' => '2b'}, 'l' => {'null' => '2d'}, '(hl)' => {'null' => '35'}, 'sp' => {'null' => '3b'}, 'a' => {'null' => '3d'}, 'ix' => {'null' => 'dd 2b'}, 'iy' => {'null' => 'fd 2b'}, 'ixpo' => {'null' => 'dd 35'}, 'iypo' => {'null' => 'fd 35'}}, 'pop' => {'bc' => {'null' => 'c1'}, 'de' => {'null' => 'd1'}, 'hl' => {'null' => 'e1'}, 'af' => {'null' => 'f1'}, 'ix' => {'null' => 'dd e1'}, 'iy' => {'null' => 'fd e1'}}, 'push' => {'bc' => {'null' => 'c5'}, 'de' => {'null' => 'd5'}, 'hl' => {'null' => 'e5'}, 'af' => {'null' => 'f5'}, 'ix' => {'null' => 'dd e5'}, 'iy' => {'null' => 'fd e5'}}, 'jr' => {'nz' => {'d1b' => '20'}, 'z' => {'d1b' => '28'}, 'nc' => {'d1b' => '30'}, 'c' => {'d1b' => '38'}, 'd1b' => {'null' => '18'}}, 'jp' => {'nz' => {'d2b' => 'c2'}, 'z' => {'d2b' => 'ca'}, 'nc' => {'d2b' => 'd2'}, 'c' => {'d2b' => 'da'}, 'po' => {'d2b' => 'e2'}, 'pe' => {'d2b' => 'ea'}, 'p' => {'d2b' => 'f2'}, 'm' => {'d2b' => 'fa'}, '(hl)' => {'null' => 'e9'}, '(ix)' => {'null' => 'dd e9'}, '(iy)' => {'null' => 'fd e9'}, 'd2b' => {'null' => 'c3'}}, 'call' => {'nz' => {'d2b' => 'c4'}, 'z' => {'d2b' => 'cc'}, 'nc' => {'d2b' => 'd4'}, 'c' => {'d2b' => 'dc'}, 'po' => {'d2b' => 'e4'}, 'pe' => {'d2b' => 'ec'}, 'p' => {'d2b' => 'f4'}, 'm' => {'d2b' => 'fc'}, 'd2b' => {'null' => 'cd'}}, 'rst' => {'00' => {'null' => 'c7'}, '08' => {'null' => 'cf'}, '10' => {'null' => 'd7'}, '18' => {'null' => 'df'}, '20' => {'null' => 'e7'}, '28' => {'null' => 'ef'}, '30' => {'null' => 'f7'}, '38' => {'null' => 'ff'}}, 'ret' => {'nz' => {'null' => 'c0'}, 'z' => {'null' => 'c8'}, 'nc' => {'null' => 'd0'}, 'c' => {'null' => 'd8'}, 'po' => {'null' => 'e0'}, 'pe' => {'null' => 'e8'}, 'p' => {'null' => 'f0'}, 'm' => {'null' => 'f8'}, 'null' => {'null' => 'c9'}}, 'bit' => {'0' => {'b' => 'cb 40', 'c' => 'cb 41', 'd' => 'cb 42', 'e' => 'cb 43', 'h' => 'cb 44', 'l' => 'cb 45', '(hl)' => 'cb 46', 'a' => 'cb 47', 'ixpo' => 'dd cb 46', 'iypo' => 'fd cb 46'}, '1' => {'b' => 'cb 48', 'c' => 'cb 49', 'd' => 'cb 4a', 'e' => 'cb 4b', 'h' => 'cb 4c', 'l' => 'cb 4d', '(hl)' => 'cb 4e', 'a' => 'cb 4f', 'ixpo' => 'dd cb 4e', 'iypo' => 'fd cb 4e'}, '2' => {'b' => 'cb 50', 'c' => 'cb 51', 'd' => 'cb 52', 'e' => 'cb 53', 'h' => 'cb 54', 'l' => 'cb 55', '(hl)' => 'cb 56', 'a' => 'cb 57', 'ixpo' => 'dd cb 56', 'iypo' => 'fd cb 56'}, '3' => {'b' => 'cb 58', 'c' => 'cb 59', 'd' => 'cb 5a', 'e' => 'cb 5b', 'h' => 'cb 5c', 'l' => 'cb 5d', '(hl)' => 'cb 5e', 'a' => 'cb 5f', 'ixpo' => 'dd cb 5e', 'iypo' => 'fd cb 5e'}, '4' => {'b' => 'cb 60', 'c' => 'cb 61', 'd' => 'cb 62', 'e' => 'cb 63', 'h' => 'cb 64', 'l' => 'cb 65', '(hl)' => 'cb 66', 'a' => 'cb 67', 'ixpo' => 'dd cb 66', 'iypo' => 'fd cb 66'}, '5' => {'b' => 'cb 68', 'c' => 'cb 69', 'd' => 'cb 6a', 'e' => 'cb 6b', 'h' => 'cb 6c', 'l' => 'cb 6d', '(hl)' => 'cb 6e', 'a' => 'cb 6f', 'ixpo' => 'dd cb 6e', 'iypo' => 'fd cb 6e'}, '6' => {'b' => 'cb 70', 'c' => 'cb 71', 'd' => 'cb 72', 'e' => 'cb 73', 'h' => 'cb 74', 'l' => 'cb 75', '(hl)' => 'cb 76', 'a' => 'cb 77', 'ixpo' => 'dd cb 76', 'iypo' => 'fd cb 76'}, '7' => {'b' => 'cb 78', 'c' => 'cb 79', 'd' => 'cb 7a', 'e' => 'cb 7b', 'h' => 'cb 7c', 'l' => 'cb 7d', '(hl)' => 'cb 7e', 'a' => 'cb 7f', 'ixpo' => 'dd cb 7e', 'iypo' => 'fd cb 7e'}}, 'set' => { '0' => {'b' => 'cb c0', 'c' => 'cb c1', 'd' => 'cb c2', 'e' => 'cb c3', 'h' => 'cb c4', 'l' => 'cb c5', '(hl)' => 'cb c6', 'a' => 'cb c7', 'ixpo' => 'dd cb c6', 'iypo' => 'fd cb c6'}, '1' => {'b' => 'cb c8', 'c' => 'cb c9', 'd' => 'cb ca', 'e' => 'cb cb', 'h' => 'cb cc', 'l' => 'cb cd', '(hl)' => 'cb ce', 'a' => 'cb cf', 'ixpo' => 'dd cb ce', 'iypo' => 'fd cb ce'}, '2' => {'b' => 'cb d0', 'c' => 'cb d1', 'd' => 'cb d2', 'e' => 'cb d3', 'h' => 'cb d4', 'l' => 'cb d5', '(hl)' => 'cb d6', 'a' => 'cb d7', 'ixpo' => 'dd cb d6', 'iypo' => 'fd cb d6'}, '3' => {'b' => 'cb d8', 'c' => 'cb d9', 'd' => 'cb da', 'e' => 'cb db', 'h' => 'cb dc', 'l' => 'cb dd', '(hl)' => 'cb de', 'a' => 'cb df', 'ixpo' => 'dd cb de', 'iypo' => 'fd cb de'}, '4' => {'b' => 'cb e0', 'c' => 'cb e1', 'd' => 'cb e2', 'e' => 'cb e3', 'h' => 'cb e4', 'l' => 'cb e5', '(hl)' => 'cb e6', 'a' => 'cb e7', 'ixpo' => 'dd cb e6', 'iypo' => 'fd cb e6'}, '5' => {'b' => 'cb e8', 'c' => 'cb e9', 'd' => 'cb ea', 'e' => 'cb eb', 'h' => 'cb ec', 'l' => 'cb ed', '(hl)' => 'cb ee', 'a' => 'cb ef', 'ixpo' => 'dd cb ee', 'iypo' => 'fd cb ee'}, '6' => {'b' => 'cb f0', 'c' => 'cb f1', 'd' => 'cb f2', 'e' => 'cb f3', 'h' => 'cb f4', 'l' => 'cb f5', '(hl)' => 'cb f6', 'a' => 'cb f7', 'ixpo' => 'dd cb f6', 'iypo' => 'fd cb f6'}, '7' => {'b' => 'cb f8', 'c' => 'cb f9', 'd' => 'cb fa', 'e' => 'cb fb', 'h' => 'cb fc', 'l' => 'cb fd', '(hl)' => 'cb fe', 'a' => 'cb ff', 'ixpo' => 'dd cb fe', 'iypo' => 'fd cb fe'}}, 'res' => {'0' => {'b' => 'cb 80', 'c' => 'cb 81', 'd' => 'cb 82', 'e' => 'cb 83', 'h' => 'cb 84', 'l' => 'cb 85', '(hl)' => 'cb 86', 'a' => 'cb 87', 'ixpo' => 'dd cb 86', 'iypo' => 'fd cb 86'}, '1' => {'b' => 'cb 88', 'c' => 'cb 89', 'd' => 'cb 8a', 'e' => 'cb 8b', 'h' => 'cb 8c', 'l' => 'cb 8d', '(hl)' => 'cb 8e', 'a' => 'cb 8f', 'ixpo' => 'dd cb 8e', 'iypo' => 'fd cb 8e'}, '2' => {'b' => 'cb 90', 'c' => 'cb 91', 'd' => 'cb 92', 'e' => 'cb 93', 'h' => 'cb 94', 'l' => 'cb 95', '(hl)' => 'cb 96', 'a' => 'cb 97', 'ixpo' => 'dd cb 96', 'iypo' => 'fd cb 96'}, '3' => {'b' => 'cb 98', 'c' => 'cb 99', 'd' => 'cb 9a', 'e' => 'cb 9b', 'h' => 'cb 9c', 'l' => 'cb 9d', '(hl)' => 'cb 9e', 'a' => 'cb 9f', 'ixpo' => 'dd cb 9e', 'iypo' => 'fd cb 9e'}, '4' => {'b' => 'cb a0', 'c' => 'cb a1', 'd' => 'cb a2', 'e' => 'cb a3', 'h' => 'cb a4', 'l' => 'cb a5', '(hl)' => 'cb a6', 'a' => 'cb a7', 'ixpo' => 'dd cb a6', 'iypo' => 'fd cb a6'}, '5' => {'b' => 'cb a8', 'c' => 'cb a9', 'd' => 'cb aa', 'e' => 'cb ab', 'h' => 'cb ac', 'l' => 'cb ad', '(hl)' => 'cb ae', 'a' => 'cb af', 'ixpo' => 'dd cb ae', 'iypo' => 'fd cb ae'}, '6' => {'b' => 'cb b0', 'c' => 'cb b1', 'd' => 'cb b2', 'e' => 'cb b3', 'h' => 'cb b4', 'l' => 'cb b5', '(hl)' => 'cb b6', 'a' => 'cb b7', 'ixpo' => 'dd cb b6', 'iypo' => 'fd cb b6'}, '7' => {'b' => 'cb b8', 'c' => 'cb b9', 'd' => 'cb ba', 'e' => 'cb bb', 'h' => 'cb bc', 'l' => 'cb bd', '(hl)' => 'cb be', 'a' => 'cb bf', 'ixpo' => 'dd cb be', 'iypo' => 'fd cb be'}}, 'and' => {'b' => {'null' => 'a0'}, 'c' => {'null' => 'a1'}, 'd' => {'null' => 'a2'}, 'e' => {'null' => 'a3'}, 'h' => {'null' => 'a4'}, 'l' => {'null' => 'a5'}, '(hl)' => {'null' => 'a6'}, 'a' => {'null' => 'a7'}, 'd1b' => {'null' => 'e6'}, 'ixpo' => {'null' => 'dd a6'}, 'iypo' => {'null' => 'fd a6'}}, 'xor' => {'b' => {'null' => 'a8'}, 'c' => {'null' => 'a9'}, 'd' => {'null' => 'aa'}, 'e' => {'null' => 'ab'}, 'h' => {'null' => 'ac'}, 'l' => {'null' => 'ad'}, '(hl)' => {'null' => 'ae'}, 'a' => {'null' => 'af'}, 'd1b' => {'null' => 'ee'}, 'ixpo' => {'null' => 'dd ae'}, 'iypo' => {'null' => 'fd ae'}}, 'or' => {'b' => {'null' => 'b0'}, 'c' => {'null' => 'b1'}, 'd' => {'null' => 'b2'}, 'e' => {'null' => 'b3'}, 'h' => {'null' => 'b4'}, 'l' => {'null' => 'b5'}, '(hl)' => {'null' => 'b6'}, 'a' => {'null' => 'b7'}, 'd1b' => {'null' => 'f6'}, 'ixpo' => {'null' => 'dd b6'}, 'iypo' => {'null' => 'fd b6'}}, 'cp' => {'b' => {'null' => 'b8'}, 'c' => {'null' => 'b9'}, 'd' => {'null' => 'ba'}, 'e' => {'null' => 'bb'}, 'h' => {'null' => 'bc'}, 'l' => {'null' => 'bd'}, '(hl)' => {'null' => 'be'}, 'a' => {'null' => 'bf'}, 'd1b' => {'null' => 'fe'}, 'ixpo' => {'null' => 'dd be'}, 'iypo' => {'null' => 'fd be'}}, 'add' => {'a' => {'b' => '80', 'c' => '81', 'd' => '82', 'e' => '83', 'h' => '84', 'l' => '85', '(hl)' => '86', 'a' => '87', 'd1b' => 'c6', 'ixpo' => 'dd 86', 'iypo' => 'fd 86'}, 'ix' => {'bc' => 'dd 09', 'de' => 'dd 19', 'ix' => 'dd 29', 'sp' => 'dd 39'}, 'iy' => {'bc' => 'fd 09', 'de' => 'fd 19', 'iy' => 'fd 29', 'sp' => 'fd 39'}, 'hl' => {'bc' => '09', 'de' => '19', 'hl' => '29', 'sp' => '39'}}, 'adc' => {'a' => {'b' => '88', 'c' => '89', 'd' => '8a', 'e' => '8b', 'h' => '8c', 'l' => '8d', '(hl)' => '8e', 'a' => '8f', 'd1b' => 'ce', 'ixpo' => 'dd 8e', 'iypo' => 'fd 8e'}, 'hl' => {'bc' => 'ed 4a', 'de' => 'ed 5a', 'hl' => 'ed 6a', 'sp' => 'ed 7a'}}, 'sub' => {'b' => {'null' => '90'}, 'c' => {'null' => '91'}, 'd' => {'null' => '92'}, 'e' => {'null' => '93'}, 'h' => {'null' => '94'}, 'l' => {'null' => '95'}, '(hl)'=> {'null' => '96'}, 'a' => {'null' => '97'}, 'd1b' => {'null' => 'd6'}, 'ixpo'=> {'null' => 'dd 96'}, 'iypo'=> {'null' => 'fd 96'}}, 'sbc' => {'b' => {'null' => '98'}, 'c' => {'null' => '99'}, 'd' => {'null' => '9a'}, 'e' => {'null' => '9b'}, 'h' => {'null' => '9c'}, 'l' => {'null' => '9d'}, '(hl)'=> {'null' => '9e'}, 'a' => {'null' => '9f', 'd1b' => 'de'}, 'd1b' => {'null' => 'de'}, 'ixpo'=> {'null' => 'dd 9e'}, 'iypo'=> {'null' => 'fd 9e'}, 'hl' => {'bc' => 'ed 42', 'de' => 'ed 52', 'hl' => 'ed 62', 'sp' => 'ed 72'}}, 'ex' => {'af' => {'af\'' => '08'}, '(sp)'=> {'hl' => 'e3', 'ix' => 'dd e3', 'iy' => 'fd e3'}, 'de' => {'hl' => 'eb'}}, 'im' => {'0' => {'null' => 'ed 46'}, '1' => {'null' => 'ed 56'}, '2' => {'null' => 'ed 5e'}}, 'rlc' => {'b' => {'null' => 'cb 00'}, 'c' => {'null' => 'cb 01'}, 'd' => {'null' => 'cb 02'}, 'e' => {'null' => 'cb 03'}, 'h' => {'null' => 'cb 04'}, 'l' => {'null' => 'cb 05'}, '(hl)'=> {'null' => 'cb 06'}, 'a' => {'null' => 'cb 07'}, 'ixpo'=> {'null' => 'dd cb 06'}, 'iypo'=> {'null' => 'fd cb 06'}}, 'rrc' => {'b' => {'null' => 'cb 08'}, 'c' => {'null' => 'cb 09'}, 'd' => {'null' => 'cb 0a'}, 'e' => {'null' => 'cb 0b'}, 'h' => {'null' => 'cb 0c'}, 'l' => {'null' => 'cb 0d'}, '(hl)'=> {'null' => 'cb 0e'}, 'a' => {'null' => 'cb 0f'}, 'ixpo'=> {'null' => 'dd cb 0e'}, 'iypo'=> {'null' => 'fd cb 0e'}}, 'rl' => {'b' => {'null' => 'cb 10'}, 'c' => {'null' => 'cb 11'}, 'd' => {'null' => 'cb 12'}, 'e' => {'null' => 'cb 13'}, 'h' => {'null' => 'cb 14'}, 'l' => {'null' => 'cb 15'}, '(hl)'=> {'null' => 'cb 16'}, 'a' => {'null' => 'cb 17'}, 'ixpo'=> {'null' => 'dd cb 16'}, 'iypo'=> {'null' => 'fd cb 16'}}, 'rr' => {'b' => {'null' => 'cb 18'}, 'c' => {'null' => 'cb 19'}, 'd' => {'null' => 'cb 1a'}, 'e' => {'null' => 'cb 1b'}, 'h' => {'null' => 'cb 1c'}, 'l' => {'null' => 'cb 1d'}, '(hl)'=> {'null' => 'cb 1e'}, 'a' => {'null' => 'cb 1f'}, 'ixpo'=> {'null' => 'dd cb 1e'}, 'iypo'=> {'null' => 'fd cb 1e'}}, 'sla' => {'b' => {'null' => 'cb 20'}, 'c' => {'null' => 'cb 21'}, 'd' => {'null' => 'cb 22'}, 'e' => {'null' => 'cb 23'}, 'h' => {'null' => 'cb 24'}, 'l' => {'null' => 'cb 25'}, '(hl)'=> {'null' => 'cb 26'}, 'a' => {'null' => 'cb 27'}, 'ixpo'=> {'null' => 'dd cb 26'}, 'iypo'=> {'null' => 'fd cb 26'}}, 'sra' => {'b' => {'null' => 'cb 28'}, 'c' => {'null' => 'cb 29'}, 'd' => {'null' => 'cb 2a'}, 'e' => {'null' => 'cb 2b'}, 'h' => {'null' => 'cb 2c'}, 'l' => {'null' => 'cb 2d'}, '(hl)' => {'null' => 'cb 2e'}, 'a' => {'null' => 'cb 2f'}, 'ixpo' => {'null' => 'dd cb 2e'}, 'iypo' => {'null' => 'fd cb 2e'}}, 'srl' => {'b' => {'null' => 'cb 38'}, 'c' => {'null' => 'cb 39'}, 'd' => {'null' => 'cb 3a'}, 'e' => {'null' => 'cb 3b'}, 'h' => {'null' => 'cb 3c'}, 'l' => {'null' => 'cb 3d'}, '(hl)' => {'null' => 'cb 3e'}, 'a' => {'null' => 'cb 3f'}, 'ixpo' => {'null' => 'dd cb 3e'}, 'iypo' => {'null' => 'fd cb 3e'}}, 'in' => {'b' => {'(c)' => 'ed 40'}, 'c' => {'(c)' => 'ed 48'}, 'd' => {'(c)' => 'ed 50'}, 'e' => {'(c)' => 'ed 58'}, 'h' => {'(c)' => 'ed 60'}, 'l' => {'(c)' => 'ed 68'}, 'a' => {'(c)' => 'ed 78', 'ia1b' => 'db'}}, 'out' => {'(c)' => {'b' => 'ed 41', 'c' => 'ed 49', 'd' => 'ed 51', 'e' => 'ed 59', 'h' => 'ed 61', 'l' => 'ed 69', 'a' => 'ed 79'}, 'ia1b' => {'a' => 'd3'}}, 'ld' => {'(bc)' => {'a' => '02'}, 'a' => {'(bc)' => '0a', '(de)' => '1a', 'b' => '78', 'c' => '79', 'd' => '7a', 'e' => '7b', 'h' => '7c', 'l' => '7d', '(hl)' => '7e', 'a' => '7f', 'i' => 'ed 57', 'r' => 'ed 5f', 'd1b' => '3e', 'ia2b' => '3a', 'ixpo' => 'dd 7e', 'iypo' => 'fd 7e'}, '(de)' => {'a' => '12'}, 'b' => {'b' => '40', 'c' => '41', 'd' => '42', 'e' => '43', 'h' => '44', 'l' => '45', '(hl)' => '46', 'a' => '47', 'd1b' => '06', 'ixpo' => 'dd 46', 'iypo' => 'fd 46'}, 'c' => {'b' => '48', 'c' => '49', 'd' => '4a', 'e' => '4b', 'h' => '4c', 'l' => '4d', '(hl)' => '4e', 'a' => '4f', 'd1b' => '0e', 'ixpo' => 'dd 4e', 'iypo' => 'fd 4e'}, 'd' => {'b' => '50', 'c' => '51', 'd' => '52', 'e' => '53', 'h' => '54', 'l' => '55', '(hl)' => '56', 'a' => '57', 'd1b' => '16', 'ixpo' => 'dd 56', 'iypo' => 'fd 56'}, 'e' => {'b' => '58', 'c' => '59', 'd' => '5a', 'e' => '5b', 'h' => '5c', 'l' => '5d', '(hl)' => '5e', 'a' => '5f', 'd1b' => '1e', 'ixpo' => 'dd 5e', 'iypo' => 'fd 5e'}, 'h' => {'b' => '60', 'c' => '61', 'd' => '62', 'e' => '63', 'h' => '64', 'l' => '65', '(hl)' => '66', 'a' => '67', 'd1b' => '26', 'ixpo' => 'dd 66', 'iypo' => 'fd 66'}, 'l' => {'b' => '68', 'c' => '69', 'd' => '6a', 'e' => '6b', 'h' => '6c', 'l' => '6d', '(hl)' => '6e', 'a' => '6f', 'd1b' => '2e', 'ixpo' => 'dd 6e', 'iypo' => 'fd 6e'}, '(hl)' => {'b' => '70', 'c' => '71', 'd' => '72', 'e' => '73', 'h' => '74', 'l' => '75', 'a' => '77', 'd1b' => '36'}, 'sp' => {'hl' => 'f9', 'ix' => 'dd f9', 'iy' => 'fd f9', 'd2b' => '31', 'ia2b' => 'ed 7b'}, 'r' => {'a' => 'ed 4f'}, 'i' => {'a' => 'ed 47'}, 'bc' => {'d2b' => '01', 'ia2b' => 'ed 4b'}, 'de' => {'d2b' => '11', 'ia2b' => 'ed 5b'}, 'hl' => {'d2b' => '21', 'ia2b' => '2a'}, 'ix' => {'d2b' => 'dd 21', 'ia2b' => 'dd 2a'}, 'iy' => {'d2b' => 'fd 21', 'ia2b' => 'fd 2a'}, 'ia2b' => {'hl' => '22', 'a' => '32', 'ix' => 'dd 22', 'iy' => 'fd 22', 'bc' => 'ed 43', 'de' => 'ed 53', 'sp' => 'ed 77'}, 'ixpo' => {'b' => 'dd 70', 'c' => 'dd 71', 'd' => 'dd 72', 'e' => 'dd 73', 'h' => 'dd 74', 'l' => 'dd 75', 'a' => 'dd 77'}, 'iypo' => {'b' => 'fd 70', 'c' => 'fd 71', 'd' => 'fd 72', 'e' => 'fd 73', 'h' => 'fd 74', 'l' => 'fd 75', 'a' => 'fd 77'}}, 'djnz' => {'d1b' => {'null' => '10'}}); # Main loop to open files and read/write them. open (SOURCE, "< z80code.s") or die "Couldn't open source file."; open (DEST, "> z80code.o") or die "Couldn't open destination file."; while (<SOURCE>) { print DEST encode($_)."\n"; } close DEST; close SOURCE; sub encode{ # Tokenise the line and return if empty. my $line = $_[0]; chomp ($line); if (!$line && defined($line)) { return (""); } $line = lc ($line); my $duplicate = $line; $line =~ tr/,/ /; my @tokens = split /\s/, $line; @tokens = grep $_ ne '', @tokens; @tokens = grep !($_ =~ m/ /), @tokens; # Process 2nd and 3rd tokens, replacing with their datatype and # storing the data if appropriate. Otherwise leave alone. my $data; foreach $_(@tokens[1..2]) { unless (defined($_)) { $_ = 'null'; next; } if ($_ =~ m/^[0-9a-f]{4}h$/) { $data = $_; $data =~ tr/h//d; $_ = 'd2b'; # Data or address, 2 bytes long } elsif ($_ =~ m/^[0-9a-f]{2}h$/) { $data = $_; $data =~ tr/h//d; $_ = 'd1b'; # Data or offset, 1 byte long } elsif ($_ =~ m/^\([0-9a-f]{4}h\)$/) { $data = $_; $data =~ tr/\(\)h//d; $_= 'ia2b'; # Indirect address, 2 bytes long } elsif ($_ =~ m/^\([0-9a-f]{2}h\)$/) { $data = $_; $data =~ tr/h\(\)//d; $_ = 'ia1b'; # Indirect address, 1 bytes long } elsif ($_ =~ m/^\(iy\+[0-9a-f]{2}h\)$/) { $data = $_; $data =~ tr/\(\)iy\+h//d; $_ = 'iypo'; # Index iy plus offset } elsif ($_ =~ m/^\(ix\+[0-9a-f]{2}h\)$/) { $data = $_; $data =~ tr/\(\)ix\+h//d; $_ = 'ixpo'; # Index ix plus offset } } # Get the correct opcode from the array or return error msg. my $answer = $opcodes{$tokens[0]}{$tokens[1]}{$tokens[2]}; unless ($answer) { return ("Instruction not found = \"$duplicate\""); } else { # Get data and return as a hex byte or pair of hex bytes. $answer .= ' '; if ($data && $data =~ m/^[0-9a-f]{4}$/) { $data = substr($data, 0, 2).' '.substr($data, 2, 2); } $answer .= $data ? $data : ''; return ($answer); } }
Notes - The assembler takes Z80 assembly language instructions and turns them into the relevant opcodes, expressed as hex bytes. The instructions should be written in the standard form - eg. ld a,(hl) - with the following caveats...
  • All data or address hex digits in code - eg. ld a,33h - should be postfixed with the letter h. The program currently does not accept addresses or data in any other base. At some point, I'll get round to writing it so that it will accept it in decimal, binary and as a quoted ASCII character also.
  • rst commands are the exception to the above - eg. rst 08, rst 10 etc...
  • I haven't added the ability to use comments yet and there is no register or memory tracing functionality.

Comments - I've actually written two versions of this program: The first splits the hash into many smaller subsections and uses (even more!) if() {} constructions, for which reason it is far more messy but it runs about an order of magnitude faster (160 lines/s versus 16 lines/s.) The reason I prefer the version given above is that it is much 'cleaner' in terms of understanding (and hence functionality is more easily added) and I wrote and tested them both on a P120 laptop, which is hardly a high-end machine, so this disadvantage will be offset by a faster machine.

I hope that somebody finds it useful, or at least diverting. As I progress further with little bits which need doing, I'll update it.

Update - rejigged and tightened the code slightly to use an array-slice rather than simply repeating two very similar sections of code.

Update^2 - Thanks to Tachyon for goading me into altering the scope of %opcodes so that the code runs about two orders of magnitude faster. I had to user vars qw(%opcodes); because I'm forced to code in Perl 5.005.03

Update^3 - As Tachyon further points out, I don't actually need the use vars qw() because I've already declared %opcodes. I really need to go back and read up on lexical scoping ;-)

Elgon

"What this book tells me is that goose-stepping morons, such as yourself, should read books instead of burning them."
       - Dr. Jones Snr, Indiana Jones and the Last Crusade

Comment on Z80 Assembler -> Hex Opcode
Select or Download Code
Re: Z80 Assembler -> Hex Opcode
by steves (Curate) on Feb 09, 2003 at 01:52 UTC

    The timing here is perfect. I was cleaning up the storage room next to my computer room here at home in the basement. What did I dig up but my first computer: a Kaypro 2, complete with a Z80 processor. I also found the box that had all its accessories, including a 300 baud acoustic coupler. Yikes.

Re: Z80 Assembler -> Hex Opcode
by tachyon (Chancellor) on Feb 09, 2003 at 11:31 UTC

    You do realise that you are forcing perl to redefine your hash with every call to your sub don't you!!!! By moving the hash definition out of the sub this will run so many orders of magnitude faster it is not funny (roughly 50,000 lines per second in my testing on a mid range single processor PIII 1.2GHz server....)

    # first define our hash (just the once not for every bloody line!!!!!! + :o) my %opcodes = ( blah ); open (SOURCE, "<z80code.s") or die "Couldn't open source file."; open (DEST, ">z80code.o") or die "Couldn't open destination file."; while (<SOURCE>) { print DEST encode($_)."\n"; } sub encode{ # blah }

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

      Maybe he's trying to emulate the speed too. 8-)

        Heh heh heh

        cheers

        tachyon

        s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

      Hi Tachyon,

      I did indeed realise this, however in the code as you have written it the declaration of %opcodes is in a different scope to that of the subroutine and hence, all you get returned is an error. I am not sure exactly how to access the hash from the subroutine's scope - %main::opcodes ???

      I did also originally run the program without the encode routines as a separate sub and it didn't appear to run any faster.

      Thanks,

      Elgon

      Update: I tried running the program as a simple loop, without the sub as before, and it took about 1 second instead of 36 or so to run. Must have declared the hash inside the loop the first time. Oops. Time to go back to the Blue Camel and re-read the sections on scoping and packages :-)

      Update^2: I've been trying to do what you suggest by passing a reference to %opcodes to the subroutine along with the line and then saying local *hash = shift; a la blue camel page 294 but this isn't liked either. FYI I'm using Perl 5.005 so use of our is right out.

      Update^3: See root node.

      "What this book tells me is that goose-stepping morons, such as yourself, should read books instead of burning them."
             - Dr. Jones Snr, Indiana Jones and the Last Crusade

        With the example I posted %opcodes is in main::, so too the sub is in main:: - ergo and therefore same scope, no errors, runs as posted. You don't need the use vars *and* the my declaration for %opcodes. One or the other will pacify strict...

        # declare this in implicit main:: package my %here = ( in => ' main' ); run(); sub run { # we are still in main:: here, so we can access %hash just fine print "I am still ", %here }

        cheers

        tachyon

        s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: CUFP [id://233706]
Approved by ybiC
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (14)
As of 2014-07-31 17:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (250 votes), past polls