-
Notifications
You must be signed in to change notification settings - Fork 10
/
gen_alu
executable file
·161 lines (137 loc) · 5.52 KB
/
gen_alu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/perl
#
# Generate contents of the ROM ALU
# (c) 2017 Warren Toomey, GPL3.
use strict;
use warnings;
use constant {
DADD => 0, # A + B decimal
DSUB => 1, # A - B decimal
AND => 2, # A & B
OR => 3, # A | B
XOR => 4, # A ^ B
INCA => 5, # A + 1
BFLAGS => 6, # 0, flags set to B's value
ZERO => 7, # 0
ADD => 8, # A + B binary
SUB => 9, # A - B binary
PASSA => 10, # A
PASSB => 11, # B
MULLO => 12, # A * B binary, low nibble
MULHI => 13, # A * B binary, high nibble
DIV => 14, # A / B binary
MOD => 15, # A % B binary
};
my @ROM;
foreach my $Asel ( 0 .. 1 ) {
foreach my $Cin ( 0 .. 1 ) {
foreach my $lowopcode ( 0 .. 7 ) {
# Include Asel as part of the ALUop
my $ALUop= $lowopcode +($Asel << 3);
foreach my $A ( 0 .. 15 ) {
foreach my $B ( 0 .. 15 ) {
my $result;
# printf("ALUop %d, A %d, B %d ", $ALUop, $A, $B);
# Unsigned BCD operation
if ( ($ALUop eq DADD) || ($ALUop eq DSUB) ) {
# Result is zero for inputs > 9
if ( ( $A > 9 ) || ( $B > 9 ) ) {
$result = 0;
}
else {
$result = ($ALUop eq DADD) ? $A + $B + $Cin : $A - $B - $Cin;
}
# Work out any carry and zero. Never negative or overflow
my ( $n, $z, $v, $c ) = ( 0, 0, 0, 0 );
if ( $result > 9 ) {
$c = 1;
$result = $result - 10; # Back to single digit
}
if ( $result < 0 ) {
$c = 1;
$result = $result + 10; # Back to single digit
}
$z = 1 if ( $result == 0 );
# Create the ROM value
my $romval = ( $n << 3 ) + ( $z << 2 ) + ( $v << 1 ) + $c +
( $result << 4 );
# printf("Cin %d result %d ", $Cin, $result);
# printf("nzvc %d%d%d%d, romval %d ", $n, $z, $v, $c, $romval);
# Store in the ROM
my $location = ( $Asel << 12 ) + ( $Cin << 11 ) +
( $lowopcode << 8 ) + ( $A << 4 ) + $B;
$ROM[$location] = $romval;
# printf("Storing %x: %x\n", $location, $romval);
next;
}
# Everything else is binary
$result = $A & $B if ( $ALUop eq AND );
$result = $A | $B if ( $ALUop eq OR );
$result = $A ^ $B if ( $ALUop eq XOR );
$result = $A if ( $ALUop eq PASSA );
$result = $B if ( $ALUop eq PASSB );
$result = $A + $B + $Cin if ( $ALUop eq ADD );
$result = $A - $B - $Cin if ( $ALUop eq SUB );
$result = $A + 1 if ( $ALUop eq INCA );
$result = 0 if ( $ALUop eq ZERO );
$result = 0 if ( $ALUop eq BFLAGS );
if ( $ALUop eq MOD ) {
$result = ($B != 0) ? ($A % $B) : 0; # Mod by zero protection
}
if ( $ALUop eq DIV ) {
$result = ($B != 0) ? int($A / $B) : 0; # Div by zero protection
}
$result = ($A * $B) & 0xf if ( $ALUop eq MULLO );
$result = ($A * $B) >> 4 if ( $ALUop eq MULHI );
my $bit5 = $result & 0x10;
$result &= 0xf;
my ( $n, $z, $v, $c ) = ( 0, 0, 0, 0 );
$n = 1 if ( $result & 0x8 );
$z = 1 if ( $result == 0 );
$c = 1 if $bit5;
# Get the sign bits for both inputs and the result
my $asign = $A & 0x8;
my $bsign = $B & 0x8;
my $rsign = $result & 0x8;
# Inputs have same sign, different from result sign
$v = 1 if ( ( $asign == $bsign ) && ( $rsign != $asign ) );
# But override all of the above for BFLAGS
if ( $ALUop eq BFLAGS ) {
$n= (($B & 0x8) >> 3);
$z= (($B & 0x4) >> 2);
$v= (($B & 0x2) >> 1);
$c= ($B & 0x1);
}
# Create the ROM value
my $romval = ( $n << 3 ) + ( $z << 2 ) + ( $v << 1 ) + $c +
( $result << 4 );
# Store in the ROM
my $location = ( $Asel << 12) +
( $Cin << 11 ) + ( $lowopcode << 8 ) + ( $A << 4 ) + $B;
$ROM[$location] = $romval;
# printf("Storing %x: %x\n", $location, $romval);
}
}
}
}
}
# Write out the ROM
open( my $OUT, ">", "alu.rom" ) || die("Can't write to alu.rom: $!\n");
print( $OUT "v2.0 raw\n" );
for my $i ( 0 .. ( 2**13 - 1 ) ) {
printf( $OUT "%x ", $ROM[$i] ? $ROM[$i] : 0 );
print( $OUT "\n" ) if ( ( $i % 8 ) == 7 );
}
close($OUT);
# Debug
#for my $i ( 0 .. ( 2**13 - 1 ) ) {
# printf("%x: %x\n", $i, $ROM[$i] ? $ROM[$i] : 0 );
#}
# Create an image for a real ROM
open( $OUT, ">", "alu.img" ) || die("Can't write to alu.img: $!\n");
for my $i ( 0 .. ( 2**13 - 1 ) ) {
my $c = pack( 'C', $ROM[$i] ? $ROM[$i] : 0 );
print( $OUT $c );
}
close($OUT);
exit(0);