root/lang/ruby/misc/rz80as/rz80as.rb @ 2374

Revision 2374, 26.7 kB (checked in by mokehehe, 6 years ago)
Line 
1#!/usr/local/bin/ruby -Ku
2# Z80 アセンブラ
3
4# ラベルだけの行(:なし)でエラーが出る
5
6require 'optparse'
7
8REG_IHL = 6                             # (HL)
9REG_A = 7                               # A
10
11REG_HL = 2                              # HL
12
13# ラベルに使える文字
14RE_1 = /[A-Za-z_\#@\$]/o                        # 先頭に使える文字
15RE_2 = /[A-Za-z_0-9\#@\$]/o             # 2文字目以降に使える文字
16RE_LABEL = /#{RE_1}#{RE_2}*/o
17
18# オペランドに使える文字
19RE_OPERAND = /[\w_$()+\-*\/,\#@'! \t]+/o
20
21# 8 bit register
22Reg8 = {'B'=>0, 'C'=>1, 'D'=>2, 'E'=>3, 'H'=>4, 'L'=>5, '(HL)'=>6, 'A'=>7}
23
24# 16 bit register
25Reg16_SP = {'BC'=>0, 'DE'=>1, 'HL'=>2, 'SP'=>3}
26
27# 16 bit register
28Reg16_AF = {'BC'=>0, 'DE'=>1, 'HL'=>2, 'AF'=>3}
29
30# 16bit register indirect
31Reg16Indirect = {'(BC)'=>0, '(DE)'=>1, '(HL)'=>2}
32
33# AF or AF'
34RegAF = {'AF'=>0, "AF'"=>1}
35
36# condition
37Cond = {'NZ'=>0, 'Z'=>1, 'NC'=>2, 'C'=>3}
38
39# condition2
40Cond2 = {'NZ'=>0, 'Z'=>1, 'NC'=>2, 'C'=>3, 'PO'=>4, 'PE'=>5, 'P'=>6, 'M'=>7}
41
42# index register
43IndexReg = {'IX'=>0, 'IY'=>1}
44
45# I or R
46RegIR = {'I'=>0, 'R'=>1}
47
48# this is label?
49def label?(val)
50        val.kind_of?(String)
51end
52
53# オペランドをカンマで分割
54def divide_operand(operand)
55        re = /[\w_$()+\-*\/'! \t]+/o
56        if /(#{re})(?:,(#{re}))?/o =~ operand
57                opr1 = $1 && $1.strip
58                opr2 = $2 && $2.strip
59                return opr1, opr2
60        end
61        return nil, nil
62end
63
64# インデックスレジスタ間接?
65def is_index_register_indirect?(str)
66        if %r!^\(I(X|Y)\s*([+\-*/].*)?\)$! =~ str
67                reg = $1 == 'X' ? 0 : 1
68                return [reg, 0]
69        else
70                nil
71        end     
72end
73
74###############################################################################
75
76# 式の計算
77# 再帰下降法
78
79def to_bin(str)
80        val = 0
81        str.each_byte {|ch| val = (val << 1) + (ch - ?0)}
82        val
83end
84
85class EvalExp
86        #==== 式の評価
87        #symbol_table ::        シンボルテーブル(ハッシュ)
88        #str ::                         評価する式の文字列
89        # 式の値を返す
90        def eval(symbol_table, str)
91                @symbol_table = symbol_table
92                @str = str
93
94                get_token
95                val = eval_plusminus
96                return val, @str
97        end
98
99private
100
101        #==== トークン切り出し
102        def get_token
103                case @str
104                when /^\s*(\d[0-9A-Fa-f]*)(H|h)/o                       # 0ABCDH
105                        @token = :number
106                        @val = $1.hex
107                when /^\s*([01]+)(B|b)/o                                        # 1010B
108                        @token = :number
109                        @val = to_bin $1
110                when /^\s*0(?:x|X)([0-9A-Fa-f]+)/o                      # 0x1234
111                        @token = :number
112                        @val = $1.hex
113                when /^\s*0(?:b|B)([01]+)/o                                     # 0b0101
114                        @token = :number
115                        @val = to_bin $1
116                when /^\s*(\d+)/o                                                       # 1234
117                        @token = :number
118                        @val = $1.to_i
119                when /'(.*?)'/o                                                         # '...'
120                        @token = :string
121                        @val = $1
122                when /^\s*\+/o                                                          # +
123                        @token = :plus
124                when /^\s*\-/o                                                          # -
125                        @token = :minus
126                when /^\s*\*/o                                                          # *
127                        @token = :mul
128                when /^\s*\//o                                                          # /
129                        @token = :div
130                when /^\s*(#{RE_LABEL})/o                                       # シンボル
131                        @token = :symbol
132                        @val = $1
133                when /^\s*$/o                                                           # 終わり
134                        @token = :end
135                else
136                        @token = :illegal
137                        return
138                end
139
140                @str = $'
141        end
142
143        #==== +-の評価
144        def eval_plusminus
145                val = eval_muldiv
146                if val
147                        while @token == :plus || @token == :minus
148                                tok = @token
149                                get_token
150                                v2 = eval_muldiv
151                                break unless v2
152
153                                if tok == :plus
154                                        val += v2
155                                else
156                                        val -= v2
157                                end
158                        end
159                end
160                val
161        end
162
163        #==== */の評価
164        def eval_muldiv
165                val = eval_factor
166                if val
167                        while @token == :mul || @token == :div
168                                tok = @token
169                                get_token
170                                v2 = eval_factor
171                                break unless v2
172
173                                if tok == :mul
174                                        val *= v2
175                                else
176                                        val /= v2
177                                end
178                        end
179                end
180                val
181        end
182
183        #==== 因子
184        def eval_factor
185                str = @str
186
187                case @token
188                when :number, :string
189                        get_token
190                        @val
191                when :symbol
192                        get_token
193                        if @symbol_table.has_key? @val
194                                @symbol_table[@val]
195                        else
196                                raise "undefined symbol '#{@val}'"
197                        end
198                when :plus, :minus
199                        tok = @token
200                        get_token
201                        if @token == :number
202                                @val = -@val if tok == :minus
203                                get_token
204                                @val
205                        else
206                                raise "illegal exp '#{str}'"
207                        end
208                else
209                        raise "illegal exp '#{str}'"
210                end
211        end
212end
213
214
215###############################################################################
216
217#=== アセンブラ
218class Z80As
219        #==== 結果をダンプ
220        def dump
221                p @label_table
222        end
223
224        #==== ソースファイルをアセンブルする
225        #戻り値:   false = ファイル読み込み失敗
226        #                       0 = アセンブル成功
227        #                       > 0 = エラーの個数
228        def assemble(srcfn, opt)
229                unless File.exist? srcfn
230                        $stderr.puts "#{srcfn}: File not found"
231                        return false
232                end
233
234                @label_table = {}
235                @srcfn = srcfn
236                @error_num = 0
237
238                assemble_pass( 1 )
239                if @error_num == 0
240                        @f_out = open(opt[:outfn], "wb")
241                        unless @f_out
242                                error "Can't open output file (#{opt[:outfn]})"
243                                return false
244                        end
245                        if opt[:listfn]
246                                @f_list = open(opt[:listfn], "w")
247                                unless @f_list
248                                        error "Can't open lst file (#{opt[:listfn]})"
249                                        return false
250                                end
251                        end
252
253                        assemble_pass( 2 )
254
255                        @f_out.close
256                        @f_list.close   if @f_list
257                end
258
259                return @error_num
260        end
261
262private
263
264        #==== エラー
265        def error(msg)
266                $stderr.puts "#{@srcfn}(#{@lineno}): #{msg}"
267                @error_num += 1
268        end
269
270        #==== 文法エラー
271        def syntax_error(line)
272                error "syntax error: #{line}"
273        end
274
275        #==== ラベル定義
276        def define_label(name, val)
277                @label_table[name] = val
278        end
279
280        #==== ラベル参照
281        def refer_label(name)
282                @label_table[name]
283        end
284
285        #==== リスト用に出力
286        def dump_list(adr, codes, line)
287                if @f_list
288                        if adr
289                                @f_list.printf "%04X: ", adr
290                        else
291                                @f_list.print "    : "
292                        end
293
294                        if codes
295                                codes.each do |c|
296                                        @f_list.printf "%02X", c
297                                end
298                        end
299                        (4 - (codes ? codes.size : 0)).times { @f_list.print "  " }
300                        @f_list.print "\t", line, "\n"
301                end
302        end
303
304        #==== パスごとの処理
305        def assemble_pass(pass)
306                @pass = pass
307
308                f = open(@srcfn)
309                if !f
310                        error "Can't open file"
311                else
312                        @adr = 0
313                        @lineno = 0
314
315                        re_label = RE_LABEL
316                        re_opecode = /[A-Za-z]+/o
317                        re_operand = RE_OPERAND
318
319                        while line = f.gets
320                                @lineno += 1
321                                @label_table['$'] = @adr
322
323                                line.chomp!
324                                unless /^(?:(?:(#{re_label})(?::\s*|\s+)|\s+)(?:(#{re_opecode})(?:\s+(#{re_operand}))?)?)?(?:\s*;(.*))?$/o =~ line
325                                        error "illegal line"
326                                else
327                                        label = $1
328                                        opecode = $2
329                                        operand = $3
330                                        comment = $4
331
332                                        codes = dispatch_opecode label, opecode, operand, line
333
334                                        if pass == 2
335                                                # コード出力
336                                                @f_out.write codes.pack("C*")   if codes
337
338                                                # リスト出力
339                                                dump_list(@adr, codes, line)
340                                        end
341
342                                        if codes
343                                                @adr += codes.size
344                                        end
345                                end
346                        end
347
348                        if @f_list
349                                @f_list.print "\nTotalBytes: #{@adr}\n"
350                        end
351
352                        f.close
353                end
354        end
355
356        #==== オペコードによって処理する
357        def dispatch_opecode(label, opecode, operand, line)
358                uopc = opecode && opecode.upcase
359                if label
360                        if uopc == 'EQU'
361                                val = parse_immediate?(operand)
362                                define_label label, val
363                                return nil
364                        else
365                                define_label label, @adr
366                        end
367                end
368                return if !opecode
369
370                op1 = @opecode1_table[uopc]
371                if op1
372                        if !operand
373                                return op1
374                        else
375                                syntax_error line
376                        end
377                else
378                        opfunctbl = @opecode_table[uopc]
379                        if opfunctbl
380                                res = dispatch_functbl opfunctbl, opecode, operand
381                                if res
382                                        return res
383                                else
384                                        syntax_error line
385                                end
386                        else
387                                syntax_error line
388                        end
389                end
390                nil
391        end
392
393        #==== オペコードテーブルによって分岐
394        def dispatch_functbl(opfunctbl, opecode, operand)
395                opfunctbl.each do |tbl|
396                        sopr1 = tbl[0]
397                        sopr2 = tbl[1]
398                        proc = tbl[2]
399
400                        if !sopr2
401                                if !sopr1
402                                        if !operand
403                                                return proc.call
404                                        end
405                                elsif operand
406                                        vopr1 = is_operand_type? sopr1, operand.upcase, operand
407                                        if vopr1
408                                                return proc.call(vopr1)
409                                        end
410                                end
411                        else
412                                if operand && /([^,]+),(.*)/o =~ operand
413                                        operand1 = $1.strip
414                                        operand2 = $2.strip
415                                        uoperand1 = operand1.upcase
416                                        uoperand2 = operand2.upcase
417                                        vopr1 = is_operand_type? sopr1, uoperand1, operand1
418                                        if vopr1
419                                                vopr2 = is_operand_type? sopr2, uoperand2, operand2
420                                                if vopr2
421                                                        return proc.call(vopr1, vopr2)
422                                                end
423                                        end
424                                end
425                        end
426                end
427                nil
428        end
429
430
431        #==== 直値かどうかの判定がゆるいので、テーブルのあとのほうにすること
432        def parse_immediate?(str)
433                if /^\(.*\)$/ =~ str            # 間接アドレッシングなので違う(注:(a*b)+(c/d) のような式を誤判定する、がとりあえず)
434                        nil
435                else
436                        # すでにレジスタやレジスタ間接は処理されてるはず、なので直値
437                        if @pass == 1
438                                # 1パス目の場合、まだ登録されてないラベルを参照する場合があるので
439                                # 適当に値を返す
440                                0xaa55
441                        else
442                                begin
443                                        val, s = @evalexp.eval @label_table, str
444                                        if s != ''
445                                                error "illegal exp '#{s}'"
446                                        end
447                                        val
448                                rescue => excep
449                                        error excep
450                                        nil
451                                end
452                        end
453                end
454        end
455
456
457        #==== オペランドが指定の種類か?
458        def is_operand_type?(type, str, orgstr)
459                case type
460                when :reg8                              # 8ビットレジスタ?
461                        Reg8[str]
462                when :regA                              # 8ビットレジスタ?
463                        str == 'A'
464                when :reg16_SP                  # 16ビットレジスタ?
465                        Reg16_SP[str]
466                when :reg16_AF                  # 16ビットレジスタ?
467                        Reg16_AF[str]
468                when :ireg16                    # 16ビットレジスタ間接?
469                        Reg16Indirect[str]
470                when :immediate                 # 直値?
471                        val = parse_immediate? orgstr
472                        if val.kind_of?(String)
473                                # 文字列だった場合: LD A,'0' とか
474                                x = 0
475                                val.each_byte {|ch| x = (x << 8) + ch}
476                                val = x
477                        end
478                        val
479                when :regAF                             # AF or AF'?
480                        RegAF[str]
481                when :regHL                             # HL?
482                        str == 'HL'
483                when :cond                              # condition?
484                        Cond[str]
485                when :cond2                             # condition2?
486                        Cond2[str]
487                when :reg_ISP_                  # (SP)?
488                        str == '(SP)'
489                when :regDE                             # DE?
490                        str == 'DE'
491                when :reg_IHL_                  # (HL)?
492                        str == '(HL)'
493                when :regSP                             # SP?
494                        str == 'SP'
495                when :regIX                             # IX or IY?
496                        IndexReg[str]
497                when :reg_iIX_                  # (IX+a) or (IY+a)?
498                        is_index_register_indirect? str
499                when :reg_iC_                   # (C)?
500                        str == '(C)'
501                when :regIR                             # I or R?
502                        RegIR[str]
503                when :iadr                              # (nn) アドレス間接?
504                        if /\((\d+)\)/o =~ str
505                                $1.to_i
506                        end
507                when :any                               # なんでも
508                        orgstr
509                else
510                        nil
511                end
512        end
513
514        #==== コンストラクタ
515        def initialize
516                #@note:
517                #       :immediate は直値かどうかの判定がゆるいので、テーブルのあとのほうにすること
518                @opecode_table = {
519                        'LD' => [
520                                [:reg8,         :reg8,                  Proc.new {|*arg| parseLD_r_r *arg}],
521                                [:regA,         :ireg16,                Proc.new {|*arg| parseLD_A_ireg16 *arg}],
522                                [:ireg16,       :regA,                  Proc.new {|*arg| parseLD_ireg16_A *arg}],
523                                [:iadr,         :regA,                  Proc.new {|*arg| parseLD_iadr_A *arg}],
524                                [:regA,         :iadr,                  Proc.new {|*arg| parseLD_A_iadr *arg}],
525                                [:iadr,         :regHL,                 Proc.new {|*arg| parseLD_iadr_HL *arg}],
526                                [:regHL,        :iadr,                  Proc.new {|*arg| parseLD_HL_iadr *arg}],
527                                [:regSP,        :regHL,                 Proc.new {|*arg| [0xf9]}],
528                                [:iadr,         :regIX,                 Proc.new {|*arg| parseLD_iadr_IX *arg}],
529                                [:regIX,        :iadr,                  Proc.new {|*arg| parseLD_IX_iadr *arg}],
530                                [:reg8,         :reg_iIX_,              Proc.new {|*arg| parseLD_r_iIX *arg}],
531                                [:reg_iIX_,     :reg8,                  Proc.new {|*arg| parseLD_iIX_r *arg}],
532                                [:regSP,        :regIX,                 Proc.new {|dst, src| [0xdd + src * 0x20, 0xf9]}],
533                                [:iadr,         :reg16_SP,              Proc.new {|*arg| parseLD_iadr_rr *arg}],
534                                [:regIR,        :regA,                  Proc.new {|*arg| parseLD_IR_A *arg}],
535                                [:regA,         :regIR,                 Proc.new {|*arg| parseLD_A_IR *arg}],
536                                [:reg16_SP,     :iadr,                  Proc.new {|*arg| parseLD_rr_iadr *arg}],
537                                [:reg8,         :immediate,             Proc.new {|*arg| parseLD_r_n *arg}],
538                                [:reg16_SP,     :immediate,             Proc.new {|*arg| parseLD_rr_nn *arg}],
539                                [:reg_iIX_,     :immediate,             Proc.new {|*arg| parseLD_iIX_n *arg}],
540                        ],
541                        'ADD' => [
542                                [:regA,         :reg8,                  Proc.new {|*arg| parseADD_A_r *arg}],
543                                [:regHL,        :reg16_SP,              Proc.new {|*arg| parseADD_HL_rr *arg}],
544                                [:regIX,        :reg16_SP,              Proc.new {|*arg| parseADD_IX_rr *arg}],
545                                [:regIX,        :regIX,                 Proc.new {|*arg| parseADD_IX_IX *arg}],
546                                [:regA,         :reg_iIX_,              Proc.new {|*arg| parseADD_A_iIX *arg}],
547                                [:regA,         :immediate,             Proc.new {|*arg| parseADD_A_n *arg}],
548                        ],
549                        'ADC' => [
550                                [:regA,         :reg8,                  Proc.new {|*arg| parseADC_A_r *arg}],
551
552                                [:regA,         :reg_iIX_,              Proc.new {|*arg| parseADC_A_iIX *arg}],
553                                [:regHL,        :reg16_SP,              Proc.new {|*arg| parseADC_HL_rr *arg}],
554                                [:regA,         :immediate,             Proc.new {|*arg| parseADC_A_n *arg}],
555                        ],
556                        'SUB' => [
557                                [:reg8,         nil,                    Proc.new {|*arg| parseSUB_r *arg}],
558                                [:reg_iIX_,     nil,                    Proc.new {|*arg| parseSUB_iIX *arg}],
559                                [:immediate,nil,                        Proc.new {|*arg| parseSUB_n *arg}],
560                        ],
561                        'SBC' => [
562                                [:regA,         :reg8,                  Proc.new {|*arg| parseSBC_A_r *arg}],
563                                [:regA,         :reg_iIX_,              Proc.new {|*arg| parseSBC_A_iIX *arg}],
564                                [:regHL,        :reg16_SP,              Proc.new {|*arg| parseSBC_HL_rr *arg}],
565                                [:regA,         :immediate,             Proc.new {|*arg| parseSBC_A_n *arg}],
566                        ],
567                        'AND' => [
568                                [:reg8,         nil,                    Proc.new {|*arg| parseAND_r *arg}],
569                                [:reg_iIX_,     nil,                    Proc.new {|*arg| parseAND_iIX *arg}],
570                                [:immediate,nil,                        Proc.new {|*arg| parseAND_n *arg}],
571                        ],
572                        'XOR' => [
573                                [:reg8,         nil,                    Proc.new {|*arg| parseXOR_r *arg}],
574                                [:reg_iIX_,     nil,                    Proc.new {|*arg| parseXOR_iIX *arg}],
575                                [:immediate,nil,                        Proc.new {|*arg| parseXOR_n *arg}],
576                        ],
577                        'OR' => [
578                                [:reg8,         nil,                    Proc.new {|*arg| parseOR_r *arg}],
579                                [:reg_iIX_,     nil,                    Proc.new {|*arg| parseOR_iIX *arg}],
580                                [:immediate,nil,                        Proc.new {|*arg| parseOR_n *arg}],
581                        ],
582                        'CP' => [
583                                [:reg8,         nil,                    Proc.new {|*arg| parseCP_r *arg}],
584                                [:reg_iIX_,     nil,                    Proc.new {|*arg| parseCP_iIX *arg}],
585                                [:immediate,nil,                        Proc.new {|*arg| parseCP_n *arg}],
586                        ],
587                        'INC' => [
588                                [:reg8,         nil,                    Proc.new {|*arg| parseINC_r *arg}],
589                                [:reg16_SP,     nil,                    Proc.new {|*arg| parseINC_rr *arg}],
590
591                                [:regIX,        nil,                    Proc.new {|*arg| parseINC_IX *arg}],
592                                [:reg_iIX_,     nil,                    Proc.new {|*arg| parseINC_iIX *arg}],
593                        ],
594                        'DEC' => [
595                                [:reg8,         nil,                    Proc.new {|*arg| parseDEC_r *arg}],
596                                [:reg16_SP,     nil,                    Proc.new {|*arg| parseDEC_rr *arg}],
597
598                                [:regIX,        nil,                    Proc.new {|*arg| parseDEC_IX *arg}],
599                                [:reg_iIX_,     nil,                    Proc.new {|*arg| parseDEC_iIX *arg}],
600                        ],
601                        'EX' => [
602                                [:regAF,        :regAF,                 Proc.new {|*arg| [0x08]}],
603                                [:reg_ISP_,     :regHL,                 Proc.new {|*arg| [0xe3]}],
604                                [:regDE,        :regHL,                 Proc.new {|*arg| [0xeb]}],
605
606                                [:reg_ISP_,     :regIX,                 Proc.new {|dst, src| [0xdd + src * 0x20, 0xe3]}],
607                        ],
608                        'JR' => [
609                                [:cond,         :immediate,             Proc.new {|*arg| parseJR_n *arg}],
610                                [:immediate,nil,                        Proc.new {|*arg| parseJR_n *arg}],
611                        ],
612                        'JP' => [
613                                [:reg_IHL_,     nil,                    Proc.new {|*arg| [0xe9]}],
614                                [:reg_iIX_,     nil,                    Proc.new {|*arg| parseJP_iIX *arg}],
615                                [:cond2,        :immediate,             Proc.new {|*arg| parseJP_nn *arg}],
616                                [:immediate,nil,                        Proc.new {|*arg| parseJP_nn *arg}],
617                        ],
618                        'DJNZ' => [
619                                [:immediate,nil,                        Proc.new {|*arg| parseDJNZ_n *arg}],
620                        ],
621                        'PUSH' => [
622                                [:reg16_AF,     nil,                    Proc.new {|*arg| parsePUSH_rr *arg}],
623                                [:regIX,        nil,                    Proc.new {|src| [0xdd + src * 0x20, 0xe5]}],
624                        ],
625                        'POP' => [
626                                [:reg16_AF,     nil,                    Proc.new {|*arg| parsePOP_rr *arg}],
627                                [:regIX,        nil,                    Proc.new {|dst| [0xdd + dst * 0x20, 0xe1]}],
628                        ],
629                        'CALL' => [
630                                [:cond2,        :immediate,             Proc.new {|*arg| parseCALL_nn *arg}],
631                                [:immediate,nil,                        Proc.new {|*arg| parseCALL_nn *arg}],
632                        ],
633                        'RET' => [
634                                [:cond2,        nil,                    Proc.new {|*arg| parseRET *arg}],
635                                [nil,           nil,                    Proc.new {|*arg| parseRET *arg}],
636                        ],
637                        'RST' => [
638                                [:immediate,nil,                        Proc.new {|*arg| parseRST_n *arg}],
639                        ],
640                        'OUT' => [
641                                [:reg_iC_,      :reg8,                  Proc.new {|*arg| parseOUT_iC_r *arg}],
642                                [:immediate,:regA,                      Proc.new {|*arg| parseOUT_n_A *arg}],
643                        ],
644                        'IN' => [
645                                [:reg8,         :reg_iC_,               Proc.new {|*arg| parseIN_r_iC *arg}],
646                                [:regA,         :immediate,             Proc.new {|*arg| parseIN_A_n *arg}],
647                        ],
648
649                        # CB xx
650                        'RLC' => [
651                                [:reg8,         nil,                    Proc.new {|dst| [0xcb, 0x00 + dst]}],
652                                [:reg_iIX_,     nil,                    Proc.new {|dst| [0xdd + dst[0] * 0x20, 0xcb, dst[1], 0x06]}],
653                        ],
654                        'RRC' => [
655                                [:reg8,         nil,                    Proc.new {|dst| [0xcb, 0x08 + dst]}],
656                                [:reg_iIX_,     nil,                    Proc.new {|dst| [0xdd + dst[0] * 0x20, 0xcb, dst[1], 0x0e]}],
657                        ],
658                        'RL' => [
659                                [:reg8,         nil,                    Proc.new {|dst| [0xcb, 0x10 + dst]}],
660                                [:reg_iIX_,     nil,                    Proc.new {|dst| [0xdd + dst[0] * 0x20, 0xcb, dst[1], 0x16]}],
661                        ],
662                        'RR' => [
663                                [:reg8,         nil,                    Proc.new {|dst| [0xcb, 0x18 + dst]}],
664                                [:reg_iIX_,     nil,                    Proc.new {|dst| [0xdd + dst[0] * 0x20, 0xcb, dst[1], 0x1e]}],
665                        ],
666                        'SLA' => [
667                                [:reg8,         nil,                    Proc.new {|dst| [0xcb, 0x20 + dst]}],
668                                [:reg_iIX_,     nil,                    Proc.new {|dst| [0xdd + dst[0] * 0x20, 0xcb, dst[1], 0x26]}],
669                        ],
670                        'SRA' => [
671                                [:reg8,         nil,                    Proc.new {|dst| [0xcb, 0x28 + dst]}],
672                                [:reg_iIX_,     nil,                    Proc.new {|dst| [0xdd + dst[0] * 0x20, 0xcb, dst[1], 0x2e]}],
673                        ],
674                        'SRL' => [
675                                [:reg8,         nil,                    Proc.new {|dst| [0xcb, 0x38 + dst]}],
676                                [:reg_iIX_,     nil,                    Proc.new {|dst| [0xdd + dst[0] * 0x20, 0xcb, dst[1], 0x3e]}],
677                        ],
678                        'BIT' => [
679                                [:immediate,:reg8,                      Proc.new {|*arg| parseBIT_n_A *arg}],
680                                [:immediate,:reg_iIX_,          Proc.new {|*arg| parseBIT_n_iIX *arg}],
681                        ],
682                        'RES' => [
683                                [:immediate,:reg8,                      Proc.new {|*arg| parseRES_n_A *arg}],
684                                [:immediate,:reg_iIX_,          Proc.new {|*arg| parseRES_n_iIX *arg}],
685                        ],
686                        'SET' => [
687                                [:immediate,:reg8,                      Proc.new {|*arg| parseSET_n_A *arg}],
688                                [:immediate,:reg_iIX_,          Proc.new {|*arg| parseSET_n_iIX *arg}],
689                        ],
690                        'IM' => [
691                                [:immediate,nil,                        Proc.new {|*arg| parseIM_n *arg}],
692                        ],
693
694                        'DB' => [
695                                [:any,          nil,                    Proc.new {|*arg| parseDB *arg}],
696                        ],
697                        'DW' => [
698                                [:any,          nil,                    Proc.new {|*arg| parseDW *arg}],
699                        ],
700                }
701                @opecode1_table = {
702                        'NOP' =>        [0x00],
703                        'RLCA' =>       [0x07],
704                        'RRCA' =>       [0x0f],
705                        'RLA' =>        [0x17],
706                        'RRA' =>        [0x1f],
707                        'DAA' =>        [0x27],
708                        'CPL' =>        [0x2f],
709                        'SCF' =>        [0x37],
710                        'CCF' =>        [0x3f],
711                        'HALT' =>       [0x76],
712                        'EXX' =>        [0xd9],
713                        'DI' =>         [0xf3],
714                        'EI' =>         [0xfb],
715
716                        'NEG' =>        [0xed, 0x44],
717                        'RETN' =>       [0xed, 0x45],
718                        'RETI' =>       [0xed, 0x4d],
719                        'RRD' =>        [0xed, 0x67],
720                        'RLD' =>        [0xed, 0x6f],
721                        'LDI' =>        [0xed, 0xa0],
722                        'CPI' =>        [0xed, 0xa1],
723                        'INI' =>        [0xed, 0xa2],
724                        'OUTI' =>       [0xed, 0xa3],
725                        'LDD' =>        [0xed, 0xa8],
726                        'CPD' =>        [0xed, 0xa9],
727                        'IND' =>        [0xed, 0xaa],
728                        'OUTD' =>       [0xed, 0xab],
729                        'LDIR' =>       [0xed, 0xb0],
730                        'CPIR' =>       [0xed, 0xb1],
731                        'INIR' =>       [0xed, 0xb2],
732                        'OTIR' =>       [0xed, 0xb3],
733                        'LDDR' =>       [0xed, 0xb8],
734                        'CPDR' =>       [0xed, 0xb9],
735                        'INDR' =>       [0xed, 0xba],
736                        'OTDR' =>       [0xed, 0xbb],
737                }
738                @evalexp = EvalExp.new
739        end
740
741
742        ######### 命令ごとの定義
743
744        # LD reg8, reg8
745        def parseLD_r_r(dst, src)
746                if dst != REG_IHL || src != REG_IHL
747                        return [0x40 + dst * 8 + src]
748                end
749        end
750
751        # LD reg8, n
752        def parseLD_r_n(dst, src)
753                return [0x06 + dst * 8, src & 255]
754        end
755
756        # LD A, (rr)
757        def parseLD_A_ireg16(dst, src)
758                return [0x0a + src * 16]
759        end
760
761        # LD (rr), A
762        def parseLD_ireg16_A(dst, src)
763                return [0x02 + dst * 16]
764        end
765
766        # LD reg16, immediate
767        def parseLD_rr_nn(dst, src)
768                return [0x01 + dst * 16, src & 255, (src >> 8) & 255]
769        end
770
771        # LD (adr), HL
772        def parseLD_iadr_HL(dst, src)
773                return [0x22, dst & 255, (dst >> 8) & 255]
774        end
775
776        # LD HL, (adr)
777        def parseLD_HL_iadr(dst, src)
778                return [0x2a, src & 255, (src >> 8) & 255]
779        end
780
781        # LD (adr), A
782        def parseLD_iadr_A(dst, src)
783                return [0x32, dst & 255, (dst >> 8) & 255]
784        end
785
786        # LD A, (adr)
787        def parseLD_A_iadr(dst, src)
788                return [0x3a, src & 255, (src >> 8) & 255]
789        end
790
791        # ADD A, reg8
792        def parseADD_A_r(dst, src)
793                return [0x80 + src]
794        end
795
796        # ADD A, n
797        def parseADD_A_n(dst, src)
798                return [0xc6, src & 255]
799        end
800
801        # ADC A, reg8
802        def parseADC_A_r(dst, src)
803                return [0x88 + src]
804        end
805
806        # ADC A, n
807        def parseADC_A_n(dst, src)
808                return [0xce, src & 255]
809        end
810
811        # SUB reg8
812        def parseSUB_r(src)
813                return [0x90 + src]
814        end
815
816        # SUB n
817        def parseSUB_n(src)
818                return [0xd6, src & 255]
819        end
820
821        # SBC A, reg8
822        def parseSBC_A_r(dst, src)
823                return [0x98 + src]
824        end
825
826        # SBC A, n
827        def parseSBC_A_n(dst, src)
828                return [0xde, src & 255]
829        end
830
831        # AND reg8
832        def parseAND_r(src)
833                return [0xa0 + src]
834        end
835
836        # AND n
837        def parseAND_n(src)
838                return [0xe6, src & 255]
839        end
840
841        # XOR reg8
842        def parseXOR_r(src)
843                return [0xa8 + src]
844        end
845
846        # XOR n
847        def parseXOR_n(src)
848                return [0xee, src & 255]
849        end
850
851        # OR reg8
852        def parseOR_r(src)
853                return [0xb0 + src]
854        end
855
856        # OR n
857        def parseOR_n(src)
858                return [0xf6, src & 255]
859        end
860
861        # CP reg8
862        def parseCP_r(src)
863                return [0xb8 + src]
864        end
865
866        # CP n
867        def parseCP_n(src)
868                return [0xfe, src & 255]
869        end
870
871        # ADD HL, reg16
872        def parseADD_HL_rr(dst, src)
873                return [0x09 + src * 16]
874        end
875
876        # INC reg8
877        def parseINC_r(dst)
878                return [0x04 + dst * 8]
879        end
880
881        # INC reg16
882        def parseINC_rr(dst)
883                return [0x03 + dst * 16]
884        end
885
886        # DEC reg8
887        def parseDEC_r(dst)
888                return [0x05 + dst * 8]
889        end
890
891        # DEC reg16
892        def parseDEC_rr(dst)
893                return [0x0b + dst * 16]
894        end
895
896        # JR d or JR cond,d
897        def parseJR_n(param1, param2=nil)
898                if param2
899                        cond = param1
900                        ofs = param2 - (@adr + 2)
901                        return [0x20 + cond * 8, ofs & 255]
902                else
903                        ofs = param1 - (@adr + 2)
904                        return [0x18, ofs & 255]
905                end
906        end
907
908        # DJNZ d
909        def parseDJNZ_n(dst)
910                ofs = dst - (@adr + 2)
911                return [0x10, ofs & 255]
912        end
913
914        # JP d or JP cond,d
915        def parseJP_nn(param1, param2=nil)
916                if param2
917                        cond = param1
918                        dst = param2
919                        return [0xc2 + cond * 8, dst & 255, (dst >> 8) & 255]
920                else
921                        dst = param1
922                        return [0xc3, dst & 255, (dst >> 8) & 255]
923                end
924        end
925
926        # PUSH reg16
927        def parsePUSH_rr(dst)
928                return [0xc5 + dst * 16]
929        end
930
931        # POP reg16
932        def parsePOP_rr(dst)
933                return [0xc1 + dst * 16]
934        end
935
936        # CALL d or CALL cond,d
937        def parseCALL_nn(param1, param2=nil)
938                if param2
939                        cond = param1
940                        dst = param2
941                        return [0xc4 + cond * 8, dst & 255, (dst >> 8) & 255]
942                else
943                        dst = param1
944                        return [0xcd, dst & 255, (dst >> 8) & 255]
945                end
946        end
947
948        # RET or RET cond
949        def parseRET(cond=nil)
950                if cond
951                        return [0xc0 + cond * 8]
952                else
953                        return [0xc9]
954                end
955        end
956
957        # RST n
958        def parseRST_n(adr)
959                return [0xc7 + (adr & 0x38)]
960        end
961
962        # OUT n, A
963        def parseOUT_n_A(dst, src)
964                return [0xd3, dst & 255]
965        end
966
967        # IN A, n
968        def parseIN_A_n(dst, src)
969                return [0xdb, src & 255]
970        end
971
972        # BIT n, A
973        def parseBIT_n_A(dst, src)
974                return [0xcb, 0x40 + (dst & 7) * 8 + src]
975        end
976
977        # BIT n, (IX+a)
978        def parseBIT_n_iIX(dst, src)
979                ix = src[0]
980                ofs = src[1]
981                return [0xdd + ix * 0x20, 0xcb, ofs, 0x46 + (dst & 7) * 8]
982        end
983
984        # RES n, A
985        def parseRES_n_A(dst, src)
986                return [0xcb, 0x80 + (dst & 7) * 8 + src]
987        end
988
989        # RES n, (IX+a)
990        def parseRES_n_iIX(dst, src)
991                ix = src[0]
992                ofs = src[1]
993                return [0xdd + ix * 0x20, 0xcb, ofs, 0x86 + (dst & 7) * 8]
994        end
995
996        # SET n, A
997        def parseSET_n_A(dst, src)
998                return [0xcb, 0xc0 + (dst & 7) * 8 + src]
999        end
1000
1001        # SET n, (IX+a)
1002        def parseSET_n_iIX(dst, src)
1003                ix = src[0]
1004                ofs = src[1]
1005                return [0xdd + ix * 0x20, 0xcb, ofs, 0xc6 + (dst & 7) * 8]
1006        end
1007
1008
1009
1010        # DD, ED, FD
1011
1012        # LD (nn), IX
1013        def parseLD_iadr_IX(dst, src)
1014                return [0xdd + src * 0x20, 0x21, dst & 255, (dst >> 8) & 255]
1015        end
1016
1017        # LD IX, (nn)
1018        def parseLD_IX_iadr(dst, src)
1019                return [0xdd + dst * 0x20, 0x2a, src & 255, (src >> 8) & 255]
1020        end
1021
1022        # LD (IX+a), n
1023        def parseLD_iIX_n(dst, src)
1024                ix = dst[0]
1025                ofs = dst[1]
1026                return [0xdd + ix * 0x20, 0x36, ofs, src & 255]
1027        end
1028
1029        # LD r, (IX+a)
1030        def parseLD_r_iIX(dst, src)
1031                ix = src[0]
1032                ofs = src[1]
1033                return [0xdd + ix * 0x20, 0x46 + dst * 8, ofs]
1034        end
1035
1036        # LD (IX+a), r
1037        def parseLD_iIX_r(dst, src)
1038                ix = dst[0]
1039                ofs = dst[1]
1040                return [0xdd + ix * 0x20, 0x70 + src, ofs]
1041        end
1042
1043        # LD (nn), rr
1044        def parseLD_iadr_rr(dst, src)
1045                if src != REG_HL
1046                        return [0xed, 0x43 + src * 16, dst & 255, (dst >> 8) & 255]
1047                end
1048        end
1049
1050        # LD rr, (nn)
1051        def parseLD_rr_iadr(dst, src)
1052                if src != REG_HL
1053                        return [0xed, 0x4b + dst * 16, src & 255, (src >> 8) & 255]
1054                end
1055        end
1056
1057        # LD I or R, A
1058        def parseLD_IR_A(dst, src)
1059                return [0xed, 0x47 + dst * 8]
1060        end
1061
1062        # LD A, I or R
1063        def parseLD_A_IR(dst, src)
1064                return [0xed, 0x57 + src * 8]
1065        end
1066
1067        # ADD IX, reg16
1068        def parseADD_IX_rr(dst, src)
1069                if src != REG_HL
1070                        return [0xdd + dst * 0x20, 0x09 + src * 16]
1071                end
1072        end
1073
1074        # ADD IX, IX
1075        def parseADD_IX_IX(dst, src)
1076                if dst == src
1077                        return [0xdd + dst * 0x20, 0x29]
1078                end
1079        end
1080
1081        # ADD A, (IX+a)
1082        def parseADD_A_iIX(dst, src)
1083                ix = src[0]
1084                ofs = src[1]
1085                return [0xdd + ix * 0x20, 0x86, ofs]
1086        end
1087
1088        # ADC A, (IX+a)
1089        def parseADC_A_iIX(dst, src)
1090                ix = src[0]
1091                ofs = src[1]
1092                return [0xdd + ix * 0x20, 0x8e, ofs]
1093        end
1094
1095        # ADC HL, rr
1096        def parseADC_HL_rr(dst, src)
1097                return [0xed, 0x4a + src * 0x10]
1098        end
1099
1100        # SUB (IX+a)
1101        def parseSUB_iIX(src)
1102                ix = src[0]
1103                ofs = src[1]
1104                return [0xdd + ix * 0x20, 0x96, ofs]
1105        end
1106
1107        # SBC A, (IX+a)
1108        def parseSBC_A_iIX(dst, src)
1109                ix = src[0]
1110                ofs = src[1]
1111                return [0xdd + ix * 0x20, 0x9e, ofs]
1112        end
1113
1114        # AND (IX+a)
1115        def parseAND_iIX(src)
1116                ix = src[0]
1117                ofs = src[1]
1118                return [0xdd + ix * 0x20, 0xa6, ofs]
1119        end
1120
1121        # XOR (IX+a)
1122        def parseXOR_iIX(src)
1123                ix = src[0]
1124                ofs = src[1]
1125                return [0xdd + ix * 0x20, 0xae, ofs]
1126        end
1127
1128        # OR (IX+a)
1129        def parseOR_iIX(src)
1130                ix = src[0]
1131                ofs = src[1]
1132                return [0xdd + ix * 0x20, 0xb6, ofs]
1133        end
1134
1135        # CP (IX+a)
1136        def parseCP_iIX(src)
1137                ix = src[0]
1138                ofs = src[1]
1139                return [0xdd + ix * 0x20, 0xbe, ofs]
1140        end
1141
1142        # INC IX
1143        def parseINC_IX(dst)
1144                return [0xdd + dst * 0x20, 0x23]
1145        end
1146
1147        # INC (IX+a)
1148        def parseINC_iIX(dst)
1149                ix = dst[0]
1150                ofs = dst[1]
1151                return [0xdd + ix * 0x20, 0x34, ofs]
1152        end
1153
1154        # DEC IX
1155        def parseDEC_IX(dst)
1156                return [0xdd + dst * 0x20, 0x2b]
1157        end
1158
1159        # DEC (IX+a)
1160        def parseDEC_iIX(dst)
1161                ix = dst[0]
1162                ofs = dst[1]
1163                return [0xdd + ix * 0x20, 0x35, ofs]
1164        end
1165
1166        # JP (IX)
1167        def parseJP_iIX(dst)
1168                ix = dst[0]
1169                ofs = dst[1]
1170                if ofs == 0
1171                        return [0xdd + ix * 0x20, 0xe9]
1172                end
1173        end
1174
1175        # OUT (C), r
1176        def parseOUT_iC_r(dst, src)
1177                return [0xed, 0x41 + src * 8]
1178        end
1179
1180        # IN B, (C)
1181        def parseIN_r_iC(dst, src)
1182                return [0xed, 0x40 + dst * 8]
1183        end
1184
1185        # SBC HL, rr
1186        def parseSBC_HL_rr(dst, src)
1187                return [0xed, 0x42 + src * 0x10]
1188        end
1189
1190        # IM n
1191        def parseIM_n(dst)
1192                code = case dst
1193                when 0
1194                        0x46
1195                when 1
1196                        0x56
1197                when 2
1198                        0x5e
1199                else
1200                        return nil
1201                end
1202                return [0xed, code]
1203        end
1204
1205
1206        def parseDB(str)
1207                res = []
1208                loop do
1209                        if /^\s*'(.*?)'/o =~ str || /^\s*"(.*?)"/o =~ str
1210                                $1.each_byte {|ch| res << (ch & 255)}
1211                                str = $'
1212                        else
1213                                r, s = @evalexp.eval @label_table, str
1214                                str = s
1215
1216                                res << r if r
1217                        end
1218
1219                        case str
1220                        when /^\s*,/o
1221                                str = $'
1222                        when /^\s*$/o
1223                                break
1224                        else
1225                                syntax_error str
1226                        end
1227                end
1228                res
1229        end
1230
1231        def parseDW(str)
1232                res = []
1233                loop do
1234                        r, s = @evalexp.eval @label_table, str
1235                        str = s
1236
1237                        if r
1238                                res.concat [r & 255, (r >> 8) & 255]
1239                        end
1240
1241                        case str
1242                        when /^\s*,/o
1243                                str = $'
1244                        when /^\s*$/o
1245                                break
1246                        else
1247                                syntax_error
1248                        end
1249                end
1250                res
1251        end
1252end
1253
1254
1255###############################################################################
1256
1257# エントリ
1258
1259opt = {
1260        # :listfn = リストファイルを出力する場合、ファイル名
1261        # :outfn = オブジェクトファイルの出力名
1262}
1263
1264begin
1265        o = OptionParser.new
1266        o.banner = "Z80 assembler by Ruby\nusage:\t[option] srcfile\noption:"
1267        o.on('-l', 'output list file (.lst)') {|listfn| opt[:listfn] = true}
1268        o.on('-o outfn', 'set output filename (default: .com)') {|fn| opt[:outfn] = fn}
1269        o.parse!(ARGV)
1270end
1271
1272srcfn = ARGV.shift
1273if !srcfn
1274        $stderr.puts o.help
1275        exit 1
1276end
1277
1278dir = File.dirname(srcfn)
1279dir = '' if dir == '/'
1280basename = File.basename(srcfn, '.*')
1281if opt[:listfn]
1282        opt[:listfn] = "#{dir}/#{basename}.lst"
1283end
1284if !opt[:outfn]
1285        opt[:outfn] = "#{dir}/#{basename}.z8b"
1286end
1287
1288z80as = Z80As.new
1289r = z80as.assemble srcfn, opt
1290if !r
1291        exit 1
1292else
1293        err_num = r
1294        if err_num > 0
1295                $stderr.puts "#{err_num} error(s)"
1296                exit 1
1297        else
1298                exit 0
1299        end
1300end
Note: See TracBrowser for help on using the browser.