File Coverage

lib/SIRTX/VM/RegisterFile.pm
Criterion Covered Total %
statement 17 110 15.4
branch 0 48 0.0
condition 0 9 0.0
subroutine 6 19 31.5
pod 11 12 91.6
total 34 198 17.1


line stmt bran cond sub pod time code
1             # Copyright (c) 2024-2025 Philipp Schafft
2              
3             # licensed under Artistic License 2.0 (see LICENSE file)
4              
5             # ABSTRACT: module for interacting with SIRTX VM code
6              
7              
8             package SIRTX::VM::RegisterFile;
9              
10 1     1   1270 use v5.16;
  1         4  
11 1     1   7 use strict;
  1         1  
  1         43  
12 1     1   4 use warnings;
  1         2  
  1         52  
13              
14 1     1   6 use Carp;
  1         2  
  1         231  
15              
16 1     1   12 use SIRTX::VM::Register;
  1         2  
  1         96  
17              
18 1     1   10 use parent 'Data::Identifier::Interface::Userdata';
  1         2  
  1         7  
19              
20             our $VERSION = v0.12;
21              
22             my @_register_templates = (
23             # user:
24              
25             (map{{name => 'user'.$_}}
26             0 .. 7), # user registers
27             (map{{name => 'user'.$_}}
28             8 .. 31), # extended user registers
29              
30             # system:
31             {name => 'arg'}, # arg register
32             {name => 'ns'}, # namespace register
33             {name => 'error'}, # error register
34             {name => 'context'}, # context register
35             {name => 'in'}, # call input register
36             {name => 'out'}, # call output
37             {name => 'deep'}, # deep storage
38             (map{undef}
39             39 .. 60), # unassigned
40             {name => 'io'}, # I/O register
41             {name => 'rodata'}, # rodata
42             {name => 'program_text'}, # program text
43             );
44              
45              
46             sub new {
47 0     0 1   my ($pkg) = @_;
48 0           my @registers;
49             my %register_names;
50             my $self = bless {
51             physical_registers => \@registers,
52             logical_registers => [],
53             register_names => \%register_names,
54 0           logical_temperature => {map {$_ => SIRTX::VM::Register::TEMPERATURE_LUKEWARM()} 0..7},
55 0           logical_owner => {map {$_ => SIRTX::VM::Register::OWNER_MINE()} 0..7},
  0            
56             }, $pkg;
57              
58 0           for (my $i = 0; $i < scalar(@_register_templates); $i++) {
59 0           my $template = $_register_templates[$i];
60 0 0         next unless defined $template;
61              
62 0 0         $registers[$i] = SIRTX::VM::Register->_new(%{$template}, physical => $i, type => ($i >= 32 ? SIRTX::VM::Register::TYPE_SYSTEM() : SIRTX::VM::Register::TYPE_USER()));
  0            
63              
64 0 0         if (defined $template->{name}) {
65 0           $register_names{$template->{name}} = $registers[$i];
66             }
67             }
68              
69 0           $self->map_reset;
70              
71 0           return $self;
72             }
73              
74              
75             sub map_reset {
76 0     0 1   my ($self) = @_;
77              
78 0           for (my $i = 0; $i < 8; $i++) {
79 0           $self->map($i => $i);
80             }
81             }
82              
83              
84             sub map {
85 0     0 1   my ($self, $logical, $physical) = @_;
86              
87 0 0 0       if ($logical < 0 || $logical >= 8) {
88 0           croak 'Bad logical register: '.$logical;
89             }
90              
91 0 0         if (!ref($physical)) {
92 0           $physical = $self->get_physical($physical);
93             }
94              
95 0           $self->{logical_registers}[$logical] = $physical;
96             }
97              
98              
99             sub get_physical {
100 0     0 1   my ($self, $physical) = @_;
101 0 0         return $physical if ref $physical;
102 0   0       return $self->{physical_registers}[$physical] // croak 'Bad physical register: '.$physical;
103             }
104              
105              
106             sub get_logical {
107 0     0 1   my ($self, $logical) = @_;
108 0   0       return $self->{logical_registers}[$logical] // croak 'Bad logical register: '.$logical;
109             }
110              
111              
112             sub get_physical_by_name {
113 0     0 1   my ($self, $name) = @_;
114              
115 0 0         if (ref $name) {
    0          
    0          
116 0           return $name;
117             } elsif ($name =~ /^r([0-9]+)$/) {
118 0           return $self->get_logical($1);
119             } elsif (defined(my $r = $self->{register_names}{$name})) {
120 0           return $r;
121             }
122              
123 0           croak 'Unknown register: '.$name;
124             }
125              
126             # deprecated alias:
127             *get_by_name = *get_physical_by_name;
128              
129             sub get_logical_by_name {
130 0     0 0   my ($self, $name) = @_;
131 0 0         if ($name =~ /^r([0-9]+)$/) {
    0          
132 0           return int($1);
133             } elsif (defined(my $r = $self->{register_names}{$name})) {
134 0           return $self->get_logical_by_physical($r);
135             }
136              
137 0           croak 'Unknown register: '.$name;
138             }
139              
140              
141             sub get_logical_by_physical {
142 0     0 1   my ($self, $physical) = @_;
143              
144 0           $physical = $self->get_physical($physical);
145              
146 0           for (my $i = 0; $i < 8; $i++) {
147 0 0         if ($self->{logical_registers}[$i] == $physical) {
148 0           return $i;
149             }
150             }
151              
152 0           croak 'Register is not mapped';
153             }
154              
155              
156             sub register_owner {
157 0     0 1   my ($self, $register, $n) = @_;
158              
159 0 0         if (ref $register) {
    0          
160 0           return $register->owner($n);
161             } elsif ($register =~ /^r([0-9]+)$/) {
162 0           my $logical = int($1);
163 0 0         $self->{logical_owner}{$logical} = $n if defined $n;
164 0           return $self->{logical_owner}{$logical};
165             } else {
166 0           return $self->get_physical_by_name($register)->owner($n);
167             }
168             }
169              
170              
171             sub register_temperature {
172 0     0 1   my ($self, $register, $n) = @_;
173              
174 0 0         if (ref $register) {
    0          
175 0           return $register->temperature($n);
176             } elsif ($register =~ /^r([0-9]+)$/) {
177 0           my $logical = int($1);
178 0 0         $self->{logical_temperature}{$logical} = $n if defined $n;
179 0           return $self->{logical_temperature}{$logical};
180             } else {
181 0           return $self->get_physical_by_name($register)->temperature($n);
182             }
183             }
184              
185              
186             sub expand {
187 0     0 1   my ($self, @args) = @_;
188 0           my @res;
189              
190 0           foreach my $reg (@args) {
191 0 0         if ($reg eq 'r*') {
    0          
    0          
192 0           push(@res, map {'r'.$_} 0..7);
  0            
193             } elsif ($reg eq 'user*') {
194 0           push(@res, map {'user'.$_} 0..31);
  0            
195             } elsif ($reg eq 'system*') {
196 0           push(@res, grep {defined} map {scalar(eval {$self->get_physical($_)->name})} 32..63);
  0            
  0            
  0            
197             } else {
198 0           push(@res, $reg);
199             }
200             }
201              
202 0           return @res;
203             }
204              
205              
206             sub clone {
207 0     0 1   my ($self) = @_;
208 0           my @registers;
209             my %register_names;
210             my $clone = bless {
211             physical_registers => \@registers,
212             logical_registers => [],
213             register_names => \%register_names,
214 0           logical_temperature => {%{$self->{logical_temperature}}},
215 0           logical_owner => {%{$self->{logical_owner}}},
  0            
216             }, __PACKAGE__;
217              
218             # clone registers:
219 0           foreach my $register (@{$self->{physical_registers}}) {
  0            
220 0 0         if (defined $register) {
221 0           my $c = $register->clone;
222 0           push(@registers, $c);
223              
224 0 0         if (defined(my $name = $c->name)) {
225 0           $register_names{$name} = $c;
226             }
227             } else {
228 0           push(@registers, undef);
229             }
230             }
231              
232             # clone map:
233 0           for (my $i = 0; $i < scalar(@{$self->{logical_registers}}); $i++) {
  0            
234 0           $clone->map($i => $self->get_logical($i)->physical);
235             }
236              
237 0           return $clone;
238             }
239              
240             # ---- Private helpers ----
241              
242             sub _physical_name_by_number {
243 0     0     my ($pkg, $number) = @_;
244 0           my $template = $_register_templates[$number];
245 0 0         return defined($template) ? $template->{name} : undef;
246             }
247              
248             1;
249              
250             __END__