| 1 |
2 |
ja_rd |
################################################################################
|
| 2 |
|
|
# uasm.pl : light8080 core microcode assembler
|
| 3 |
|
|
################################################################################
|
| 4 |
|
|
# Usage: perl uasm.pl <microcode file name> <command list>
|
| 5 |
|
|
#
|
| 6 |
|
|
# The command list is a space-separated sequence of the following:
|
| 7 |
|
|
#
|
| 8 |
|
|
# -lst : Shows a listing of the assembled microinstructions next to their
|
| 9 |
|
|
# assembler source lines. Not very useful because it does not show
|
| 10 |
|
|
# assembler pragma, label or comment lines.
|
| 11 |
|
|
# -labels : Shows a list of all defined labels with their address and the
|
| 12 |
|
|
# number of times they are used.
|
| 13 |
|
|
# -bitfields: Shows a list of all the different microinstructions generated,
|
| 14 |
|
|
# plus the number of times they are used. Might be useful to encode
|
| 15 |
|
|
# the microinstructions and save rom bits.
|
| 16 |
|
|
# -instructions: Shows a list of all defined instructions with the address their
|
| 17 |
|
|
# microcode starts at.
|
| 18 |
|
|
# -rom_bin : Shows a raw list of all the binary microinstructions.
|
| 19 |
|
|
# -rom_vhdl : Shows a vhdl block containing the microcode rom declaration.
|
| 20 |
|
|
#
|
| 21 |
|
|
# If none of the above commands is given, the program just exits silently. Any
|
| 22 |
|
|
# unrecognized command is silently ignored.
|
| 23 |
|
|
################################################################################
|
| 24 |
|
|
# Assembler format (informal definition, source is the ultimate reference!):
|
| 25 |
|
|
#
|
| 26 |
|
|
#<microinstruction line> :=
|
| 27 |
62 |
ja_rd |
# [<label>] | (*1)
|
| 28 |
|
|
# <operand stage control> ; <ALU stage control> [; [<flag list>]] |
|
| 29 |
|
|
# JSR <destination address>|TJSR <destination address>
|
| 30 |
2 |
ja_rd |
#
|
| 31 |
|
|
#<label> := {':' immediately followed by a common identifier}
|
| 32 |
|
|
#<destination address> := {an identifier defined as label anywhere in the file}
|
| 33 |
|
|
#<operand stage control> := <op_reg> = <op_src> | NOP
|
| 34 |
|
|
#<op_reg> := T1 | T2
|
| 35 |
|
|
#<op_src> := <register> | DI | <IR register>
|
| 36 |
|
|
#<IR register> := {s}|{d}|{p}0|{p}1 (*3)
|
| 37 |
|
|
#<register> := _a|_b|_c|_d|_e|_h|_l|_f|_a|_ph|_pl|_x|_y|_z|_w|_sh|_sl|
|
| 38 |
|
|
#<ALU stage control> := <alu_dst> = <alu_op> | NOP
|
| 39 |
|
|
#<alu_dst> := <register> | DO
|
| 40 |
|
|
#<alu_op> := add|adc|sub|sbb| and|orl|not|xrl| rla|rra|rlca|rrca| aaa|
|
| 41 |
|
|
# t1|rst|daa|cpc|sec|psw
|
| 42 |
|
|
#<flag list> := <flag> [, <flag> ...]
|
| 43 |
|
|
#<flag> := #decode|#di|#ei|#io|#auxcy|#clrt1|#halt|#end|#ret|#rd|#wr|#setacy
|
| 44 |
64 |
ja_rd |
# #ld_al|#ld_addr|#fp_c|#fp_r|#fp_rc|#clr_cy_ac (*2)
|
| 45 |
2 |
ja_rd |
#
|
| 46 |
62 |
ja_rd |
# *1 Labels appear alone by themselves in a line
|
| 47 |
|
|
# *2 There are some restrictions on the flags that can be used together
|
| 48 |
|
|
# *3 Registers are specified by IR field
|
| 49 |
2 |
ja_rd |
#
|
| 50 |
|
|
################################################################################
|
| 51 |
|
|
# ALU operations
|
| 52 |
|
|
#
|
| 53 |
|
|
#Operation Encoding ALU result
|
| 54 |
|
|
#===============================================================================
|
| 55 |
|
|
#ADD 001100 T2 + T1
|
| 56 |
|
|
#ADC 001101 T2 + T1 + CY
|
| 57 |
|
|
#SUB 001110 T2 - T1
|
| 58 |
|
|
#SBB 001111 T2 – T1 - CY
|
| 59 |
|
|
#AND 000100 T1 AND T2
|
| 60 |
|
|
#ORL 000101 T1 OR T2
|
| 61 |
|
|
#NOT 000110 NOT T1
|
| 62 |
|
|
#XRL 000111 T1 XOR T2
|
| 63 |
|
|
#RLA 000000 8080 RLC
|
| 64 |
|
|
#RRA 000001 8080 RRC
|
| 65 |
|
|
#RLCA 000010 8080 RAL
|
| 66 |
|
|
#RRCA 000011 8080 RAR
|
| 67 |
|
|
#T1 010111 T1
|
| 68 |
|
|
#RST 011111 8*IR(5..3), as per RST instruction
|
| 69 |
|
|
#DAA 101000 DAA T1 (but only after executing 2 in a row)
|
| 70 |
|
|
#CPC 101100 UNDEFINED (CY complemented)
|
| 71 |
|
|
#SEC 101101 UNDEFINED (CY set)
|
| 72 |
|
|
################################################################################
|
| 73 |
|
|
# Flags :
|
| 74 |
|
|
# --- Flags from group 1: use only one of these
|
| 75 |
|
|
# #decode : Load address counter and IR with contents of data input lines,
|
| 76 |
|
|
# thus starting opcode decoging.
|
| 77 |
|
|
# #ei : Set interrupt enable register.
|
| 78 |
|
|
# #di : Reset interrupt enable register.
|
| 79 |
|
|
# #io : Activate io signal for 1st cycle.
|
| 80 |
|
|
# #auxcy : Use aux carry instead of regular carry for this operation.
|
| 81 |
|
|
# #clrt1 : Clear T1 at the end of 1st cycle.
|
| 82 |
|
|
# #halt : Jump to microcode address 0x07 without saving return value.
|
| 83 |
|
|
#
|
| 84 |
|
|
# --- Flags from group 2: use only one of these
|
| 85 |
|
|
# #setacy : Set aux carry at the start of 1st cycle (used for ++).
|
| 86 |
|
|
# #end : Jump to microinstruction address 3 after the present m.i.
|
| 87 |
|
|
# #ret : Jump to address saved by the last JST or TJSR m.i.
|
| 88 |
|
|
# #rd : Activate rd signal for the 2nd cycle.
|
| 89 |
|
|
# #wr : Activate wr signal for the 2nd cycle.
|
| 90 |
|
|
# --- Independent flags: no restrictions
|
| 91 |
|
|
# #ld_al : Load AL register with register bank output as read by operation 1.
|
| 92 |
|
|
# (used in memory and io access).
|
| 93 |
|
|
# #ld_addr : Load address register (H byte = register bank output as read by
|
| 94 |
|
|
# operation 1, L byte = AL).
|
| 95 |
|
|
# Activate vma signal for 1st cycle.
|
| 96 |
64 |
ja_rd |
# #clr_acy : Instruction clears CY and AC flags. Use with #fp_rc.
|
| 97 |
2 |
ja_rd |
# --- PSW update flags: use only one of these
|
| 98 |
|
|
# #fp_r : This instruction updates all PSW flags except for C.
|
| 99 |
|
|
# #fp_c : This instruction updates only the C flag in the PSW.
|
| 100 |
|
|
# #fp_rc : This instruction updates all the flags in the PSW.
|
| 101 |
|
|
################################################################################
|
| 102 |
|
|
# Read the design notes for a brief reference to the micromachine internal
|
| 103 |
|
|
# behavior, including implicit loads/erases.
|
| 104 |
|
|
################################################################################
|
| 105 |
|
|
|
| 106 |
|
|
$file = shift(@ARGV);
|
| 107 |
|
|
|
| 108 |
|
|
open(INFO, $file) or die "unable to open file '$file'\n";
|
| 109 |
|
|
@lines = <INFO>;
|
| 110 |
|
|
close(INFO);
|
| 111 |
|
|
|
| 112 |
|
|
$field2_nop = '0'.'0000'.'00'.'0'.'0'.'000000';
|
| 113 |
|
|
$field2_jsr = '0'.'0000'.'00'.'0'.'0'.'000000';
|
| 114 |
|
|
|
| 115 |
|
|
%field1_ops =
|
| 116 |
|
|
( 'nop', '000'.'000'.'00000'.'00'.'0000'.$field2_nop,
|
| 117 |
|
|
'jsr', '000'.'010'.'00000'.'00'.'0000'.$field2_jsr,
|
| 118 |
|
|
'tjsr', '000'.'100'.'00000'.'00'.'0000'.$field2_jsr,
|
| 119 |
|
|
|
| 120 |
|
|
't1 = {s}', '000'.'000'.'00101'.'01'.'0000'.$field2_nop,
|
| 121 |
|
|
't1 = {d}', '000'.'000'.'00101'.'10'.'0000'.$field2_nop,
|
| 122 |
|
|
't1 = {p}0', '000'.'000'.'00101'.'11'.'0000'.$field2_nop,
|
| 123 |
|
|
't1 = {p}1', '000'.'000'.'00101'.'11'.'0001'.$field2_nop,
|
| 124 |
|
|
't1 = di', '000'.'000'.'00100'.'00'.'0000'.$field2_nop,
|
| 125 |
|
|
't1 = _b', '000'.'000'.'00101'.'00'.'0000'.$field2_nop,
|
| 126 |
|
|
't1 = _c', '000'.'000'.'00101'.'00'.'0001'.$field2_nop,
|
| 127 |
|
|
't1 = _d', '000'.'000'.'00101'.'00'.'0010'.$field2_nop,
|
| 128 |
|
|
't1 = _e', '000'.'000'.'00101'.'00'.'0011'.$field2_nop,
|
| 129 |
|
|
't1 = _h', '000'.'000'.'00101'.'00'.'0100'.$field2_nop,
|
| 130 |
|
|
't1 = _l', '000'.'000'.'00101'.'00'.'0101'.$field2_nop,
|
| 131 |
|
|
't1 = _a', '000'.'000'.'00101'.'00'.'0111'.$field2_nop,
|
| 132 |
|
|
't1 = _f', '000'.'000'.'00101'.'00'.'0110'.$field2_nop,
|
| 133 |
|
|
't1 = _ph', '000'.'000'.'00101'.'00'.'1000'.$field2_nop,
|
| 134 |
|
|
't1 = _pl', '000'.'000'.'00101'.'00'.'1001'.$field2_nop,
|
| 135 |
|
|
't1 = _x', '000'.'000'.'00101'.'00'.'1010'.$field2_nop,
|
| 136 |
|
|
't1 = _y', '000'.'000'.'00101'.'00'.'1011'.$field2_nop,
|
| 137 |
|
|
't1 = _z', '000'.'000'.'00101'.'00'.'1100'.$field2_nop,
|
| 138 |
|
|
't1 = _w', '000'.'000'.'00101'.'00'.'1101'.$field2_nop,
|
| 139 |
|
|
't1 = _sh', '000'.'000'.'00101'.'00'.'1110'.$field2_nop,
|
| 140 |
|
|
't1 = _sl', '000'.'000'.'00101'.'00'.'1111'.$field2_nop,
|
| 141 |
|
|
|
| 142 |
|
|
't2 = {s}', '000'.'000'.'00011'.'01'.'0000'.$field2_nop,
|
| 143 |
|
|
't2 = {d}', '000'.'000'.'00011'.'10'.'0000'.$field2_nop,
|
| 144 |
|
|
't2 = {p}0', '000'.'000'.'00011'.'11'.'0000'.$field2_nop,
|
| 145 |
|
|
't2 = {p}1', '000'.'000'.'00011'.'11'.'0001'.$field2_nop,
|
| 146 |
|
|
't2 = di', '000'.'000'.'00010'.'00'.'0000'.$field2_nop,
|
| 147 |
|
|
't2 = _b', '000'.'000'.'00011'.'00'.'0000'.$field2_nop,
|
| 148 |
|
|
't2 = _c', '000'.'000'.'00011'.'00'.'0001'.$field2_nop,
|
| 149 |
|
|
't2 = _d', '000'.'000'.'00011'.'00'.'0010'.$field2_nop,
|
| 150 |
|
|
't2 = _e', '000'.'000'.'00011'.'00'.'0011'.$field2_nop,
|
| 151 |
|
|
't2 = _h', '000'.'000'.'00011'.'00'.'0100'.$field2_nop,
|
| 152 |
|
|
't2 = _l', '000'.'000'.'00011'.'00'.'0101'.$field2_nop,
|
| 153 |
|
|
't2 = _a', '000'.'000'.'00011'.'00'.'0111'.$field2_nop,
|
| 154 |
|
|
't2 = _f', '000'.'000'.'00011'.'00'.'0110'.$field2_nop,
|
| 155 |
|
|
't2 = _ph', '000'.'000'.'00011'.'00'.'1000'.$field2_nop,
|
| 156 |
|
|
't2 = _pl', '000'.'000'.'00011'.'00'.'1001'.$field2_nop,
|
| 157 |
|
|
't2 = _x', '000'.'000'.'00011'.'00'.'1010'.$field2_nop,
|
| 158 |
|
|
't2 = _y', '000'.'000'.'00011'.'00'.'1011'.$field2_nop,
|
| 159 |
|
|
't2 = _z', '000'.'000'.'00011'.'00'.'1100'.$field2_nop,
|
| 160 |
|
|
't2 = _w', '000'.'000'.'00011'.'00'.'1101'.$field2_nop,
|
| 161 |
|
|
't2 = _sh', '000'.'000'.'00011'.'00'.'1110'.$field2_nop,
|
| 162 |
|
|
't2 = _sl', '000'.'000'.'00011'.'00'.'1111'.$field2_nop
|
| 163 |
|
|
|
| 164 |
|
|
);
|
| 165 |
|
|
|
| 166 |
|
|
|
| 167 |
|
|
$re_field1 = "(".join('|',keys %field1_ops).")";
|
| 168 |
|
|
$re_field1 =~ s/\[/\\\[/g;
|
| 169 |
|
|
$re_field1 =~ s/\]/\\\]/g;
|
| 170 |
|
|
|
| 171 |
|
|
%field2_ops =
|
| 172 |
|
|
( 'add', '001100',
|
| 173 |
|
|
'adc', '001101',
|
| 174 |
|
|
'sub', '001110',
|
| 175 |
|
|
'sbb', '001111',
|
| 176 |
|
|
|
| 177 |
|
|
'and', '000100',
|
| 178 |
|
|
'orl', '000110',
|
| 179 |
|
|
'not', '000111',
|
| 180 |
|
|
'xrl', '000101',
|
| 181 |
|
|
|
| 182 |
|
|
'rla', '000000',
|
| 183 |
|
|
'rra', '000001',
|
| 184 |
|
|
'rlca', '000010',
|
| 185 |
|
|
'rrca', '000011',
|
| 186 |
|
|
|
| 187 |
|
|
'aaa', '111000',
|
| 188 |
|
|
|
| 189 |
|
|
't1', '010111',
|
| 190 |
|
|
'rst', '011111',
|
| 191 |
|
|
'daa', '101000',
|
| 192 |
|
|
'cpc', '101100',
|
| 193 |
|
|
'sec', '101101',
|
| 194 |
|
|
'psw', '110000'
|
| 195 |
|
|
);
|
| 196 |
|
|
|
| 197 |
|
|
|
| 198 |
|
|
$re_f2_ops = "(".join('|',keys %field2_ops).")";
|
| 199 |
|
|
$re_f2_ops =~ s/\[/\\\[/g;
|
| 200 |
|
|
$re_f2_ops =~ s/\]/\\\]/g;
|
| 201 |
|
|
|
| 202 |
|
|
# 'parse' command line flags into a string
|
| 203 |
|
|
$cmdline = join ':', @ARGV;
|
| 204 |
|
|
|
| 205 |
|
|
$num_line = 0;
|
| 206 |
|
|
$addr = 0;
|
| 207 |
|
|
|
| 208 |
|
|
%labels = (); # <label, address>
|
| 209 |
|
|
@label_uses = (); # <label, [addresses in which it's used]>
|
| 210 |
|
|
@undefined_targets = (); # array of <label, address in which it's used>
|
| 211 |
|
|
$num_errors = 0;
|
| 212 |
|
|
|
| 213 |
|
|
@bitfields = ();
|
| 214 |
|
|
|
| 215 |
|
|
@rom = ();
|
| 216 |
|
|
@asm = ();
|
| 217 |
|
|
@errors = ();
|
| 218 |
|
|
@num_lines = ();
|
| 219 |
|
|
|
| 220 |
|
|
%asm_to_uaddr = (); # opcode asm -> uaddress
|
| 221 |
|
|
%uaddr_to_asm = (); # uaddress -> opcode asm
|
| 222 |
|
|
|
| 223 |
|
|
%uaddr_to_pattern = (); # uaddress -> pattern
|
| 224 |
|
|
%pattern_to_uaddr = (); # pattern -> uaddress -- simulation, decoder
|
| 225 |
|
|
|
| 226 |
|
|
LINE: foreach $line (@lines) {
|
| 227 |
|
|
|
| 228 |
62 |
ja_rd |
$num_line++;
|
| 229 |
|
|
|
| 230 |
|
|
$line =~ tr/A-Z/a-z/;
|
| 231 |
|
|
$line =~ s/(--|\/\/).*//;
|
| 232 |
2 |
ja_rd |
$line =~ s/^\s*//g;
|
| 233 |
|
|
$line =~ s/\s*\$//g;
|
| 234 |
|
|
chomp($line);
|
| 235 |
|
|
|
| 236 |
|
|
$uinst = {
|
| 237 |
|
|
field_1 => '',
|
| 238 |
|
|
src => '',
|
| 239 |
|
|
special => '',
|
| 240 |
|
|
field_2 => '',
|
| 241 |
|
|
field_0 => '000000',
|
| 242 |
|
|
flags => '',
|
| 243 |
|
|
error => '',
|
| 244 |
|
|
asm => $line
|
| 245 |
|
|
};
|
| 246 |
|
|
|
| 247 |
|
|
|
| 248 |
|
|
# if line is whitespace or comment (which has been changed to whitespace)
|
| 249 |
|
|
# then skip to next line
|
| 250 |
|
|
if($line eq ''){
|
| 251 |
|
|
next;
|
| 252 |
|
|
}
|
| 253 |
|
|
|
| 254 |
62 |
ja_rd |
# if $line is a label declaration, get it and skip to next line
|
| 255 |
2 |
ja_rd |
# note labels come alone in the line, unlike other assemblers
|
| 256 |
|
|
# TODO it'd be simple to change this...
|
| 257 |
62 |
ja_rd |
if($line =~ /^\s*:(\w+)/){
|
| 258 |
|
|
# subroutine label (labels are only used for jsrs)
|
| 259 |
|
|
$labels{$1} = $addr;
|
| 260 |
|
|
next;
|
| 261 |
|
|
}
|
| 262 |
2 |
ja_rd |
|
| 263 |
|
|
# if line is a pragma, process it
|
| 264 |
|
|
if($line =~ /^\s*__/){
|
| 265 |
|
|
# TODO process pragmas __reset, __fetch, __int
|
| 266 |
|
|
|
| 267 |
|
|
#if($line =~ /^\s*__code\s+"([0|1|s|d|p|a|r]+)"/){
|
| 268 |
|
|
# we do nothing with the opcode byte; it's for reference only
|
| 269 |
|
|
#printf "%04d # %s\n",$addr,$1;
|
| 270 |
|
|
#}
|
| 271 |
|
|
if($line =~ /^\s*__asm\s+(.*)/){
|
| 272 |
|
|
# save the start address for the CPU instruction
|
| 273 |
|
|
# it will be used in the design of the decoder
|
| 274 |
|
|
$asm_to_uaddr{$1} = $addr;
|
| 275 |
|
|
$uaddr_to_asm{$addr} = $1;
|
| 276 |
|
|
}
|
| 277 |
|
|
|
| 278 |
|
|
if($line =~ /^\s*__code\s+"(.*)".*/){
|
| 279 |
|
|
# save the start address for the CPU instruction
|
| 280 |
|
|
# it will be used in the design of the decoder
|
| 281 |
|
|
$pattern_to_uaddr{$1} = $addr;
|
| 282 |
|
|
$uaddr_to_pattern{$addr} = $1;
|
| 283 |
|
|
}
|
| 284 |
|
|
|
| 285 |
|
|
|
| 286 |
|
|
next;
|
| 287 |
|
|
}
|
| 288 |
|
|
|
| 289 |
|
|
# get flags field (all text following 1st '#' included)
|
| 290 |
|
|
# remove it so we're left with 'field1 ; field2 [;]'
|
| 291 |
|
|
$line = process_flags($line);
|
| 292 |
|
|
|
| 293 |
|
|
# break line in 1 or 2 fields
|
| 294 |
|
|
@fields = split /;/, $line;
|
| 295 |
|
|
|
| 296 |
|
|
# process 1st field...
|
| 297 |
62 |
ja_rd |
$done = process_field1($fields[0]);
|
| 298 |
2 |
ja_rd |
|
| 299 |
|
|
# ...and process 2nd field if there is one (depends on field1 format)
|
| 300 |
|
|
# TODO check that there's no field2 when there shouldn't
|
| 301 |
62 |
ja_rd |
if($done != 1){
|
| 302 |
2 |
ja_rd |
$done = process_field2($fields[1]);
|
| 303 |
62 |
ja_rd |
}
|
| 304 |
2 |
ja_rd |
|
| 305 |
|
|
# finally, process extra flags produced by field1 assembly (jsr/tjsr)
|
| 306 |
|
|
process_extra_flags();
|
| 307 |
|
|
|
| 308 |
|
|
# complete bitfield with flags...
|
| 309 |
|
|
substr($uinst->{field1}, 0, 6) = $uinst->{field_0};
|
| 310 |
|
|
|
| 311 |
|
|
# Now, we already have the bitfields.
|
| 312 |
|
|
|
| 313 |
|
|
push(@rom, $uinst->{field1});
|
| 314 |
|
|
push(@asm, substr($line,0,40));
|
| 315 |
|
|
push(@num_lines, $num_line);
|
| 316 |
|
|
if($uinst->{error} eq ''){
|
| 317 |
|
|
push(@errors, '');
|
| 318 |
|
|
}
|
| 319 |
|
|
else{
|
| 320 |
|
|
push(@errors, $uinst->{error});
|
| 321 |
|
|
}
|
| 322 |
|
|
|
| 323 |
|
|
$addr++; #addr++ even for error uinsts
|
| 324 |
|
|
|
| 325 |
|
|
}
|
| 326 |
|
|
continue {
|
| 327 |
|
|
}
|
| 328 |
|
|
|
| 329 |
|
|
# Line processing finished (1st pass). Start 2nd pass and do listings
|
| 330 |
|
|
# if requested
|
| 331 |
|
|
|
| 332 |
|
|
# 2nd pass
|
| 333 |
|
|
|
| 334 |
|
|
# now we know the value of all labels, fill in address field of forward jumps
|
| 335 |
|
|
foreach $target (@undefined_targets){
|
| 336 |
|
|
@item = @{$target};
|
| 337 |
|
|
$value = to_bin($labels{$item[0]}, 8);
|
| 338 |
|
|
$adr = $item[1]*1;
|
| 339 |
|
|
|
| 340 |
62 |
ja_rd |
substr($rom[$adr], 20,2, substr($value, 0,2));
|
| 341 |
|
|
substr($rom[$adr], 26,6, substr($value, 2,6));
|
| 342 |
2 |
ja_rd |
}
|
| 343 |
|
|
|
| 344 |
|
|
foreach $bf (@rom){
|
| 345 |
|
|
push(@bitfields, $bf);
|
| 346 |
|
|
}
|
| 347 |
|
|
|
| 348 |
|
|
# listings
|
| 349 |
|
|
|
| 350 |
|
|
if($cmdline =~ /-lst/){
|
| 351 |
|
|
$do_lst = 1;
|
| 352 |
|
|
}
|
| 353 |
|
|
|
| 354 |
|
|
$i = 0;
|
| 355 |
|
|
foreach $bf (@rom){
|
| 356 |
|
|
if($do_lst){
|
| 357 |
|
|
printf "%02x %32s :: %s\n", $i, $bf, $asm[$i];
|
| 358 |
|
|
if($errors[$i] ne ''){
|
| 359 |
|
|
printf " ERROR (%d): %s\n", $num_lines[$i], $errors[$i];
|
| 360 |
|
|
}
|
| 361 |
|
|
}
|
| 362 |
|
|
|
| 363 |
|
|
$i++;
|
| 364 |
|
|
}
|
| 365 |
|
|
|
| 366 |
|
|
if($do_lst){
|
| 367 |
|
|
# completion message
|
| 368 |
|
|
printf "\nDone. %d uinsts, %d errors.\n", $addr, $num_errors;
|
| 369 |
|
|
}
|
| 370 |
|
|
|
| 371 |
|
|
# label listing
|
| 372 |
|
|
if($cmdline =~ /\-labels/){
|
| 373 |
|
|
label_list();
|
| 374 |
|
|
}
|
| 375 |
|
|
|
| 376 |
|
|
# bitfield histogram
|
| 377 |
|
|
if($cmdline =~ /\-bitfields/){
|
| 378 |
|
|
bitfield_histogram();
|
| 379 |
|
|
}
|
| 380 |
|
|
|
| 381 |
|
|
# show cpu instruction microcode addresses
|
| 382 |
|
|
if($cmdline =~ /\-instructions/){
|
| 383 |
|
|
foreach $asm (sort {$asm_to_uaddr{$a} <=> $asm_to_uaddr{$b}}(keys %asm_to_uaddr)){
|
| 384 |
|
|
$uaddress = $asm_to_uaddr{$asm};
|
| 385 |
|
|
printf "%02x %s %s\n", $uaddress, $uaddr_to_pattern{$uaddress}, $asm;
|
| 386 |
|
|
}
|
| 387 |
|
|
}
|
| 388 |
|
|
|
| 389 |
|
|
if($cmdline =~ /\-rom_vhdl/){
|
| 390 |
|
|
show_decoder_table('vhdl');
|
| 391 |
|
|
}
|
| 392 |
|
|
|
| 393 |
|
|
if($cmdline =~ /\-rom_bin/){
|
| 394 |
|
|
show_decoder_table('bin');
|
| 395 |
|
|
}
|
| 396 |
|
|
|
| 397 |
|
|
# end of main program
|
| 398 |
|
|
|
| 399 |
|
|
|
| 400 |
|
|
################################################################################
|
| 401 |
|
|
|
| 402 |
|
|
|
| 403 |
|
|
sub show_decoder_table {
|
| 404 |
|
|
|
| 405 |
|
|
my $fmat = shift(@_);
|
| 406 |
|
|
|
| 407 |
|
|
# show decoder rom contents
|
| 408 |
|
|
%decoder_hash = ();
|
| 409 |
|
|
foreach $pat (keys %pattern_to_uaddr){
|
| 410 |
|
|
$add = $pattern_to_uaddr{$pat};
|
| 411 |
|
|
$pat =~ s/[a-z]/\[01\]/g;
|
| 412 |
|
|
$decoder_hash{$pat} = $add;
|
| 413 |
|
|
}
|
| 414 |
|
|
|
| 415 |
|
|
@decoder_rom = ();
|
| 416 |
|
|
for($i = 0; $i<256; $i++){
|
| 417 |
|
|
$b = to_bin($i, 8);
|
| 418 |
|
|
$val = 0;
|
| 419 |
|
|
# We'll match the opcode to the pattern with the shortest length; that is,
|
| 420 |
|
|
# the one with the less wildcards in it. Crude but effective in this case.
|
| 421 |
|
|
$len_matched_pat = 1000;
|
| 422 |
|
|
foreach $pat (keys %decoder_hash){
|
| 423 |
|
|
if($b =~ /$pat/){
|
| 424 |
|
|
if(length($pat) < $len_matched_pat){
|
| 425 |
|
|
$val = $decoder_hash{$pat};
|
| 426 |
|
|
$len_matched_pat = length($pat);
|
| 427 |
|
|
}
|
| 428 |
|
|
#last;
|
| 429 |
|
|
}
|
| 430 |
|
|
}
|
| 431 |
|
|
push @decoder_rom, $val;
|
| 432 |
|
|
}
|
| 433 |
|
|
|
| 434 |
|
|
if($fmat eq 'vhdl'){
|
| 435 |
|
|
# print rom vhdl header...
|
| 436 |
|
|
print "type t_rom is array (0 to 511) of std_logic_vector(31 downto 0);\n";
|
| 437 |
|
|
print "signal rom : t_rom := (\n";
|
| 438 |
|
|
}
|
| 439 |
|
|
|
| 440 |
|
|
# The 1st half of the uinst rom holds 256 uinstructions
|
| 441 |
|
|
my $i=0;
|
| 442 |
|
|
foreach $bf (@rom){
|
| 443 |
|
|
if($fmat eq 'vhdl'){
|
| 444 |
|
|
printf "\"%s\", -- %03x\n", $bf, $i;
|
| 445 |
|
|
}
|
| 446 |
|
|
else{
|
| 447 |
|
|
printf "%s\n", $bf;
|
| 448 |
|
|
}
|
| 449 |
|
|
$i++;
|
| 450 |
|
|
}
|
| 451 |
|
|
# Fill remaining slots with ENDs
|
| 452 |
|
|
for(;$i<256;$i++){
|
| 453 |
|
|
my $val = '00000100000000000000000000000000';
|
| 454 |
|
|
if($fmat eq 'vhdl'){
|
| 455 |
|
|
printf "\"%s\", -- %03x\n", $val, $i;
|
| 456 |
|
|
}
|
| 457 |
|
|
else{
|
| 458 |
|
|
printf "%s\n", $val;
|
| 459 |
|
|
}
|
| 460 |
|
|
}
|
| 461 |
|
|
|
| 462 |
|
|
# The 2nd half (upper 256 entries) of the ucode rom contains a jump table
|
| 463 |
|
|
# with a jsr for each of the 256 opcodes, serving as cheap decoder:
|
| 464 |
|
|
foreach $entry (@decoder_rom){
|
| 465 |
|
|
my $val = to_bin($entry, 8);
|
| 466 |
|
|
$val = '00001000000000000000'.substr($val,0,2).'0000'.substr($val,2,6);
|
| 467 |
|
|
$i++;
|
| 468 |
|
|
if($fmat eq 'vhdl'){
|
| 469 |
|
|
printf "\"%s\"", $val;
|
| 470 |
|
|
if($i<512){
|
| 471 |
|
|
print ",";
|
| 472 |
|
|
}
|
| 473 |
|
|
else{
|
| 474 |
|
|
print " ";
|
| 475 |
|
|
}
|
| 476 |
|
|
printf " -- %03x\n", ($i - 1);
|
| 477 |
|
|
}
|
| 478 |
|
|
else{
|
| 479 |
|
|
printf "%s\n", $val;
|
| 480 |
|
|
}
|
| 481 |
|
|
}
|
| 482 |
|
|
|
| 483 |
|
|
if($fmat eq 'vhdl'){
|
| 484 |
|
|
# close vhdl declaration
|
| 485 |
|
|
print "\n);\n";
|
| 486 |
|
|
}
|
| 487 |
|
|
|
| 488 |
|
|
}
|
| 489 |
|
|
|
| 490 |
|
|
sub label_list {
|
| 491 |
|
|
# label table listing
|
| 492 |
|
|
print "\nlabels:\n";
|
| 493 |
|
|
print "---------------------------------\n";
|
| 494 |
|
|
print "label addr uses\n";
|
| 495 |
|
|
print "---------------------------------\n";
|
| 496 |
|
|
|
| 497 |
|
|
%hist_labels;
|
| 498 |
|
|
$hist_labels{$_}++ for @label_uses;
|
| 499 |
|
|
|
| 500 |
|
|
foreach $label (keys %hist_labels){
|
| 501 |
|
|
printf "%-20s %04x %d\n", $label, $labels{$label}, $hist_labels{$label};
|
| 502 |
|
|
}
|
| 503 |
|
|
}
|
| 504 |
|
|
|
| 505 |
|
|
sub bitfield_histogram {
|
| 506 |
|
|
|
| 507 |
|
|
%hist_bitfields;
|
| 508 |
|
|
$hist_bitfields{$_}++ for @bitfields;
|
| 509 |
|
|
@unique_bitfields = keys %hist_bitfields;
|
| 510 |
|
|
|
| 511 |
|
|
printf "\nbitfield usage (total: %d)\n", $#unique_bitfields;
|
| 512 |
|
|
print "------------------------------------------------\n";
|
| 513 |
|
|
print "bitfield uses\n";
|
| 514 |
|
|
print "------------------------------------------------\n";
|
| 515 |
|
|
|
| 516 |
|
|
foreach $bfield (sort sortFieldsByFrequency(keys %hist_bitfields)){
|
| 517 |
|
|
printf "%-32s %d\n", $bfield, $hist_bitfields{$bfield};
|
| 518 |
|
|
}
|
| 519 |
|
|
}
|
| 520 |
|
|
|
| 521 |
|
|
sub sortFieldsByFrequency {
|
| 522 |
|
|
$hist_bitfields{$b} <=> $hist_bitfields{$a};
|
| 523 |
|
|
}
|
| 524 |
|
|
|
| 525 |
|
|
sub process_extra_flags {
|
| 526 |
|
|
|
| 527 |
|
|
$flags1 = '';
|
| 528 |
|
|
$flags2 = '';
|
| 529 |
|
|
|
| 530 |
|
|
|
| 531 |
|
|
# first, process flags produced by 1st field processing
|
| 532 |
|
|
if($uinst->{flags} =~ /#jsr/){
|
| 533 |
|
|
if($flags2 ne ''){$error = 'incompatible flags'};
|
| 534 |
|
|
$flags2 = '010';
|
| 535 |
|
|
}
|
| 536 |
|
|
if($uinst->{flags} =~ /#tjsr/){
|
| 537 |
|
|
if($flags2 ne ''){$error = 'incompatible flags'};
|
| 538 |
|
|
$flags2 = '100';
|
| 539 |
|
|
}
|
| 540 |
|
|
|
| 541 |
|
|
$provisional_flags2 = substr($uinst->{field_0},3,3);
|
| 542 |
|
|
if($flags2 ne ''){
|
| 543 |
|
|
if($provisional_flags2 ne '000'){
|
| 544 |
|
|
$error = "flags incompatible with jsr/tjsr operation: "
|
| 545 |
|
|
.$provisional_flags2;
|
| 546 |
|
|
$num_errors++;
|
| 547 |
62 |
ja_rd |
$uinst->{error} = $error;
|
| 548 |
2 |
ja_rd |
}
|
| 549 |
|
|
else{
|
| 550 |
|
|
substr($uinst->{field_0},3,3) = $flags2;
|
| 551 |
|
|
}
|
| 552 |
|
|
}
|
| 553 |
|
|
|
| 554 |
|
|
if($uinst->{flags} =~ /#ld_al/){
|
| 555 |
|
|
substr($uinst->{field1},7,1) = '1';
|
| 556 |
|
|
}
|
| 557 |
|
|
if($uinst->{flags} =~ /#ld_addr/){
|
| 558 |
|
|
substr($uinst->{field1},6,1) = '1';
|
| 559 |
|
|
}
|
| 560 |
|
|
|
| 561 |
|
|
if($uinst->{flags} =~ /#fp_c/){
|
| 562 |
|
|
substr($uinst->{field1},22,2) = '01';
|
| 563 |
|
|
}
|
| 564 |
|
|
if($uinst->{flags} =~ /#fp_r/){
|
| 565 |
|
|
substr($uinst->{field1},22,2) = '10';
|
| 566 |
|
|
}
|
| 567 |
|
|
if($uinst->{flags} =~ /#fp_rc/){
|
| 568 |
|
|
substr($uinst->{field1},22,2) = '11';
|
| 569 |
|
|
}
|
| 570 |
64 |
ja_rd |
if($uinst->{flags} =~ /#clr_acy/){
|
| 571 |
|
|
substr($uinst->{field1},17,1) = '1';
|
| 572 |
|
|
}
|
| 573 |
2 |
ja_rd |
|
| 574 |
|
|
}
|
| 575 |
|
|
|
| 576 |
|
|
sub process_flags {
|
| 577 |
|
|
|
| 578 |
|
|
my $line = shift(@_);
|
| 579 |
|
|
|
| 580 |
|
|
$line =~ s/#/##/;
|
| 581 |
|
|
$line =~ /(.*)#(#.*)/;
|
| 582 |
|
|
|
| 583 |
|
|
$flags1 = '';
|
| 584 |
|
|
$flags2 = '';
|
| 585 |
|
|
|
| 586 |
|
|
|
| 587 |
|
|
if($1 ne ''){
|
| 588 |
|
|
$line_without_flags = $1;
|
| 589 |
|
|
$flag_str = $2;
|
| 590 |
|
|
|
| 591 |
|
|
@flags = split /,/, $flag_str;
|
| 592 |
|
|
$error = '';
|
| 593 |
|
|
|
| 594 |
|
|
if($flag_str =~ /#end/){
|
| 595 |
|
|
if($flags2 ne ''){$error = 'incompatible flags'};
|
| 596 |
|
|
$flags2 = '001';
|
| 597 |
|
|
}
|
| 598 |
|
|
if($flag_str =~ /#ret/){
|
| 599 |
|
|
if($flags2 ne ''){$error = 'incompatible flags'};
|
| 600 |
|
|
$flags2 = '011';
|
| 601 |
|
|
}
|
| 602 |
|
|
if($flag_str =~ /#rd/){
|
| 603 |
|
|
if($flags2 ne ''){$error = 'incompatible flags'};
|
| 604 |
|
|
$flags2 = '101';
|
| 605 |
|
|
}
|
| 606 |
|
|
if($flag_str =~ /#wr/){
|
| 607 |
|
|
if($flags2 ne ''){$error = 'incompatible flags'};
|
| 608 |
|
|
$flags2 = '110';
|
| 609 |
|
|
}
|
| 610 |
|
|
if($flag_str =~ /#auxcy/){
|
| 611 |
|
|
if($flags1 ne ''){$error = 'incompatible flags'};
|
| 612 |
|
|
$flags1 = '101';
|
| 613 |
|
|
}
|
| 614 |
|
|
|
| 615 |
|
|
if($flag_str =~ /#decode/){
|
| 616 |
|
|
if($flags1 ne ''){$error = 'incompatible flags'};
|
| 617 |
|
|
$flags1 = '001';
|
| 618 |
|
|
}
|
| 619 |
|
|
if($flag_str =~ /#clrt1/){
|
| 620 |
|
|
if($flags1 ne ''){$error = 'incompatible flags'};
|
| 621 |
|
|
$flags1 = '110';
|
| 622 |
|
|
}
|
| 623 |
|
|
if($flag_str =~ /#halt/){
|
| 624 |
|
|
if($flags1 ne ''){$error = 'incompatible flags'};
|
| 625 |
|
|
$flags1 = '111';
|
| 626 |
|
|
}
|
| 627 |
|
|
if($flag_str =~ /#di/){
|
| 628 |
|
|
if($flags1 ne ''){$error = 'incompatible flags'};
|
| 629 |
|
|
$flags1 = '010';
|
| 630 |
|
|
}
|
| 631 |
|
|
if($flag_str =~ /#ei/){
|
| 632 |
|
|
if($flags1 ne ''){$error = 'incompatible flags'};
|
| 633 |
|
|
$flags1 = '011';
|
| 634 |
|
|
}
|
| 635 |
|
|
if($flag_str =~ /#io/){
|
| 636 |
|
|
if($flags1 ne ''){$error = 'incompatible flags'};
|
| 637 |
|
|
$flags1 = '100';
|
| 638 |
|
|
}
|
| 639 |
|
|
if($flag_str =~ /#setacy/){
|
| 640 |
|
|
if($flags2 ne ''){$error = 'incompatible flags:'.$flags2};
|
| 641 |
|
|
$flags2 = '111';
|
| 642 |
|
|
}
|
| 643 |
|
|
|
| 644 |
|
|
if($flags2 eq ''){ $flags2 = '000';};
|
| 645 |
|
|
if($flags1 eq ''){ $flags1 = '000';};
|
| 646 |
|
|
|
| 647 |
|
|
$uinst->{field_0} = $flags1.$flags2;
|
| 648 |
|
|
|
| 649 |
|
|
# Some of the flags must be processed after the rest of the uinst
|
| 650 |
|
|
# has been assembled; save them into $uinst->{flags} for later.
|
| 651 |
|
|
|
| 652 |
|
|
if($flag_str =~ /#ld_al/){
|
| 653 |
|
|
$uinst->{flags} = $uinst->{flags}." #ld_al";
|
| 654 |
|
|
}
|
| 655 |
|
|
if($flag_str =~ /#ld_addr/){
|
| 656 |
|
|
$uinst->{flags} = $uinst->{flags}." #ld_addr";
|
| 657 |
|
|
}
|
| 658 |
|
|
if($flag_str =~ /#fp_c/){
|
| 659 |
|
|
$uinst->{flags} = $uinst->{flags}." #fp_c";
|
| 660 |
|
|
}
|
| 661 |
|
|
if($flag_str =~ /#fp_r/){
|
| 662 |
|
|
$uinst->{flags} = $uinst->{flags}." #fp_r";
|
| 663 |
|
|
}
|
| 664 |
|
|
if($flag_str =~ /#fp_rc/){
|
| 665 |
|
|
$uinst->{flags} = $uinst->{flags}." #fp_rc";
|
| 666 |
|
|
}
|
| 667 |
64 |
ja_rd |
if($flag_str =~ /#clr_acy/){
|
| 668 |
|
|
$uinst->{flags} = $uinst->{flags}." #clr_acy";
|
| 669 |
|
|
}
|
| 670 |
2 |
ja_rd |
|
| 671 |
|
|
if($error ne ''){
|
| 672 |
|
|
$num_errors++;
|
| 673 |
|
|
$uinst->{error} = $error;
|
| 674 |
|
|
};
|
| 675 |
|
|
|
| 676 |
|
|
return $line_without_flags;
|
| 677 |
|
|
}
|
| 678 |
|
|
|
| 679 |
|
|
return $line;
|
| 680 |
|
|
}
|
| 681 |
|
|
|
| 682 |
|
|
|
| 683 |
|
|
sub process_field2 {
|
| 684 |
|
|
my $field = shift(@_).";";
|
| 685 |
|
|
|
| 686 |
|
|
$field =~ s/^\s*//g;
|
| 687 |
|
|
$field =~ s/\s*;//g;
|
| 688 |
|
|
$field =~ s/\s+/ /g;
|
| 689 |
|
|
|
| 690 |
|
|
$field =~ s/A-Z/a-z/g;
|
| 691 |
|
|
|
| 692 |
|
|
|
| 693 |
|
|
# check for special field2 formats: nop
|
| 694 |
|
|
if($field =~ /(nop)/){
|
| 695 |
|
|
# field2 is nop by default
|
| 696 |
|
|
return 0;
|
| 697 |
|
|
}
|
| 698 |
|
|
|
| 699 |
|
|
|
| 700 |
|
|
if($field =~ /(_\w+|{p}0|{p}1|{d}|{s}|do) = (\w+|t1)/){
|
| 701 |
|
|
|
| 702 |
|
|
#check that dst address is the same as field1's src address
|
| 703 |
|
|
#(since they end up being the same physical bits)
|
| 704 |
|
|
@parts = split /=/, $field;
|
| 705 |
|
|
$dst = $parts[0];
|
| 706 |
|
|
$dst =~ s/\s//g;
|
| 707 |
|
|
if(($dst ne $uinst->{src})
|
| 708 |
|
|
&& ($dst ne 'do')
|
| 709 |
|
|
&& ($uinst->{src} ne 'di')
|
| 710 |
|
|
&& ($uinst->{src} ne '')){
|
| 711 |
|
|
# field mismatch
|
| 712 |
|
|
$num_errors++;
|
| 713 |
|
|
$uinst->{error} = "field source/destination address mismatch";
|
| 714 |
|
|
return 1;
|
| 715 |
|
|
}
|
| 716 |
|
|
else{
|
| 717 |
|
|
# build bitfield for field2, including those bits that overlap
|
| 718 |
|
|
# bits from field 1
|
| 719 |
|
|
|
| 720 |
|
|
if($dst eq 'do'){
|
| 721 |
|
|
substr($uinst->{field1}, 24, 1) = '1'; #ld_do
|
| 722 |
|
|
}
|
| 723 |
|
|
else{
|
| 724 |
|
|
substr($uinst->{field1}, 25, 1) = '1'; #ld_reg
|
| 725 |
|
|
|
| 726 |
|
|
if($dst eq '{p}0'){
|
| 727 |
|
|
substr($uinst->{field1}, 11, 2) = '11';
|
| 728 |
|
|
substr($uinst->{field1}, 13, 4) = '0000';
|
| 729 |
|
|
}
|
| 730 |
|
|
elsif($dst eq '{p}1'){
|
| 731 |
|
|
substr($uinst->{field1}, 11, 2) = '11';
|
| 732 |
|
|
substr($uinst->{field1}, 13, 4) = '0001';
|
| 733 |
|
|
}
|
| 734 |
|
|
elsif($dst eq '{d}'){
|
| 735 |
|
|
substr($uinst->{field1}, 11, 2) = '10';
|
| 736 |
|
|
substr($uinst->{field1}, 13, 4) = '0000';
|
| 737 |
|
|
}
|
| 738 |
|
|
elsif($dst eq '{s}'){
|
| 739 |
|
|
substr($uinst->{field1}, 11, 2) = '01';
|
| 740 |
|
|
substr($uinst->{field1}, 13, 4) = '0000';
|
| 741 |
|
|
}
|
| 742 |
|
|
else{
|
| 743 |
|
|
%regs = ( '_b',0, '_c',1, '_d',2, '_e',3,
|
| 744 |
|
|
'_h',4, '_l',5, '_f',6, '_a',7,
|
| 745 |
|
|
'_ph',8, '_pl',9, '_x',10, '_y',11,
|
| 746 |
|
|
'_z',12, '_w',13, '_sh',14, '_sl',15);
|
| 747 |
|
|
|
| 748 |
|
|
$val_reg = to_bin($regs{$dst},4);
|
| 749 |
|
|
substr($uinst->{field1}, 11, 2) = '00';
|
| 750 |
|
|
substr($uinst->{field1}, 13, 4) = $val_reg; # RD address; same as WR
|
| 751 |
|
|
}
|
| 752 |
|
|
|
| 753 |
|
|
}
|
| 754 |
|
|
|
| 755 |
|
|
# TODO deal with flag pattern
|
| 756 |
|
|
$parts[1] =~ s/\s//g;
|
| 757 |
|
|
$src = $field2_ops{$parts[1]}.'';
|
| 758 |
|
|
if($src eq ''){
|
| 759 |
|
|
$num_errors++;
|
| 760 |
|
|
$uinst->{error} = "field 2 operation unknown: [".$parts[1]."]";
|
| 761 |
|
|
return 1;
|
| 762 |
|
|
}
|
| 763 |
|
|
else{
|
| 764 |
|
|
substr($uinst->{field1},26,6) = $src;
|
| 765 |
|
|
return 0;
|
| 766 |
|
|
}
|
| 767 |
|
|
}
|
| 768 |
|
|
|
| 769 |
|
|
}
|
| 770 |
|
|
elsif($field =~ /(sec|cpc)/){
|
| 771 |
|
|
substr($uinst->{field1},26,6) = $field2_ops{$1};
|
| 772 |
|
|
}
|
| 773 |
|
|
else{
|
| 774 |
|
|
# field2 empty or invalid
|
| 775 |
|
|
$num_errors++;
|
| 776 |
|
|
$uinst->{error} = "field 2 empty or invalid: ".$re_field2;
|
| 777 |
|
|
return 1;
|
| 778 |
|
|
}
|
| 779 |
|
|
|
| 780 |
|
|
}
|
| 781 |
|
|
|
| 782 |
|
|
|
| 783 |
|
|
|
| 784 |
62 |
ja_rd |
# return !=0 when uinst is finished except for flags,
|
| 785 |
|
|
# 0 when field2 has to be processed
|
| 786 |
2 |
ja_rd |
|
| 787 |
|
|
sub process_field1 {
|
| 788 |
|
|
|
| 789 |
|
|
my $field = shift(@_).";";
|
| 790 |
|
|
|
| 791 |
|
|
$field =~ s/^\s*//g;
|
| 792 |
|
|
$field =~ s/\s*;//g;
|
| 793 |
|
|
$field =~ s/\s+/ /g;
|
| 794 |
|
|
|
| 795 |
62 |
ja_rd |
# look for special format uinsts: jsr, tjsr, nop
|
| 796 |
|
|
if($field =~ /(jsr|tjsr)\s+([_\w]+)/){
|
| 797 |
|
|
$opcode = $1;
|
| 798 |
|
|
$target = $2;
|
| 799 |
|
|
# set flag
|
| 800 |
|
|
$uinst->{flags} = $uinst->{flags}." #".$opcode." ";
|
| 801 |
|
|
|
| 802 |
|
|
# check that target is defined, otherwise tag it for 2nd pass
|
| 803 |
|
|
$target_addr = $labels{$target};
|
| 804 |
2 |
ja_rd |
|
| 805 |
62 |
ja_rd |
tag_label_use($target, $addr);
|
| 806 |
|
|
|
| 807 |
|
|
if($target_addr eq ''){
|
| 808 |
|
|
push @undefined_targets, [$target, $addr];
|
| 809 |
|
|
$code = $field1_ops{$opcode};
|
| 810 |
|
|
$uinst->{field1} = $code;
|
| 811 |
|
|
}
|
| 812 |
|
|
else{
|
| 813 |
|
|
# set up bitfield so we can fill the address in in 2nd pass
|
| 814 |
|
|
$code = $field1_ops{$opcode};
|
| 815 |
|
|
$a = to_bin($target_addr+0, 8);
|
| 816 |
|
|
substr($code, 20,2, substr($a, 0,2));
|
| 817 |
|
|
substr($code, 26,6, substr($a, 2,6));
|
| 818 |
|
|
$uinst->{field1} = $code;
|
| 819 |
|
|
}
|
| 820 |
|
|
return 1;
|
| 821 |
|
|
}
|
| 822 |
|
|
|
| 823 |
|
|
if($field =~ /nop/){
|
| 824 |
|
|
# TODO encode NOP as 1st field
|
| 825 |
|
|
$uinst->{field1} = $field1_ops{'nop'};
|
| 826 |
|
|
return 0;
|
| 827 |
|
|
}
|
| 828 |
2 |
ja_rd |
|
| 829 |
62 |
ja_rd |
# process regular field1 (register load): dst = src
|
| 830 |
|
|
|
| 831 |
2 |
ja_rd |
if($field =~ /$re_field1/){
|
| 832 |
|
|
@parts = split /=/, $field;
|
| 833 |
|
|
|
| 834 |
|
|
# if a src reg address literal is specified, it has to be the same
|
| 835 |
|
|
# address as for field2 dest; save it for later comparison.
|
| 836 |
|
|
|
| 837 |
|
|
$src = $parts[1];
|
| 838 |
|
|
$src =~ s/\s//g;
|
| 839 |
|
|
|
| 840 |
|
|
$d = $field1_ops{$field}.'';
|
| 841 |
|
|
|
| 842 |
|
|
if($d eq ''){
|
| 843 |
|
|
# unrecognized source that somehow matches pattern (e.g. _pl0)
|
| 844 |
62 |
ja_rd |
$error = "invalid source in uinst field 1";
|
| 845 |
|
|
$uinst->{field1} = $field1_ops{'nop'};
|
| 846 |
|
|
$uinst->{error} = $error;
|
| 847 |
|
|
$num_errors++;
|
| 848 |
2 |
ja_rd |
$uinst->{src} = '?';
|
| 849 |
|
|
return 1;
|
| 850 |
|
|
}
|
| 851 |
|
|
else{
|
| 852 |
|
|
$uinst->{src} = $src;
|
| 853 |
|
|
$uinst->{field1} = $d;
|
| 854 |
|
|
}
|
| 855 |
|
|
return 0;
|
| 856 |
|
|
}
|
| 857 |
|
|
else{
|
| 858 |
62 |
ja_rd |
# field1 not recognized.
|
| 859 |
|
|
$error = "uinst field 1 not recognized: '".$field."'";
|
| 860 |
|
|
$uinst->{field1} = $field1_ops{'nop'};
|
| 861 |
|
|
$uinst->{error} = $error;
|
| 862 |
|
|
$num_errors++;
|
| 863 |
2 |
ja_rd |
return 1;
|
| 864 |
|
|
}
|
| 865 |
|
|
|
| 866 |
|
|
}
|
| 867 |
|
|
|
| 868 |
|
|
sub tag_label_use {
|
| 869 |
|
|
|
| 870 |
|
|
my $label = shift(@_);
|
| 871 |
|
|
my $address = shift(@_);
|
| 872 |
|
|
|
| 873 |
|
|
push(@label_uses, $label);
|
| 874 |
|
|
|
| 875 |
|
|
}
|
| 876 |
|
|
|
| 877 |
|
|
sub to_bin {
|
| 878 |
|
|
my $number = shift(@_) * 1;
|
| 879 |
|
|
my $length = shift(@_);
|
| 880 |
|
|
|
| 881 |
|
|
$n = $number;
|
| 882 |
|
|
$r = '';
|
| 883 |
|
|
for( my $i=$length-1;$i>=0;$i--){
|
| 884 |
|
|
$d = 2 ** $i;
|
| 885 |
|
|
|
| 886 |
|
|
if($n >= $d){
|
| 887 |
|
|
$r = $r.'1';
|
| 888 |
|
|
$n = $n - $d;
|
| 889 |
|
|
}
|
| 890 |
|
|
else{
|
| 891 |
|
|
$r = $r.'0';
|
| 892 |
|
|
}
|
| 893 |
|
|
}
|
| 894 |
|
|
|
| 895 |
|
|
return $r;
|
| 896 |
|
|
}
|
| 897 |
|
|
|
| 898 |
|
|
# End of file
|