/usr/share/openmsx/scripts/_slot.tcl is in openmsx-data 0.10.0-1ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | namespace eval slot {
#
# get_selected_slot
#
set_help_text get_selected_slot \
{Returns the selected slot for the given memory page.
This proc is typically used as a helper for a larger proc.
@param page The memory page (0-3)
@result Returns a Tcl list with two elements.
First element is the primary slot (0-3).
Second element is the secondary slot (0-3) or 'X'
in case this slot was not expanded
}
proc get_selected_slot {page} {
set ps_reg [debug read "ioports" 0xA8]
set ps [expr {($ps_reg >> (2 * $page)) & 0x03}]
if {[machine_info "issubslotted" $ps]} {
set ss_reg [debug read "slotted memory" [expr {0x40000 * $ps + 0xFFFF}]]
set ss [expr {(($ss_reg ^ 255) >> (2 * $page)) & 0x03}]
} else {
set ss "X"
}
list $ps $ss
}
#
# slotselect
#
set_help_text slotselect \
{Returns a nicely formatted overview of the selected slots.}
proc slotselect {} {
set result ""
for {set page 0} {$page < 4} {incr page} {
lassign [get_selected_slot $page] ps ss
append result [format "%04X: slot %d" [expr {0x4000 * $page}] $ps]
if {$ss ne "X"} {append result "." $ss}
append result "\n"
}
return $result
}
#
# get_mapper_size
#
set_help_text get_mapper_size \
{Returns the size of the memory mapper in a given slot.
Result is 0 when there is no memory mapper in the slot.}
proc get_mapper_size {ps ss} {
set result 0
catch { ;# for multi-mem devices, but those aren't memory mappers
set device [lindex [machine_info slot $ps $ss 0] 0]
if {[debug desc $device] eq "memory mapper"} {
set result [expr {[debug size $device] / 0x4000}]
}
}
return $result
}
#
# get (rom) block size
# e.g. for a 'Konami' rom mapper it returns 8kB
# TODO it would be nice to generalize this so that it also works for memory
# mappers, or even all memory mapped devices (whether they have switchable
# blocks or not)
#
proc get_block_size {ps ss page} {
set block_size 0
catch {
set device_list [machine_info slot $ps $ss $page]
if {[llength $device_list] != 1} {return 0}
set device_info [machine_info device [lindex $device_list 0]]
set romtype [lindex $device_info 1] ;# can return ""
set romtype_info [openmsx_info romtype $romtype] ;# fails if romtype == ""
set block_size [dict get $romtype_info blocksize] ;# could fail??
}
return $block_size
}
#
# pc_in_slot
#
set_help_text pc_in_slot \
{Test whether the CPU's program counter is inside a certain slot.
Typically used to set breakpoints in specific slots.}
proc pc_in_slot {ps {ss "X"} {mapper "X"}} {
return [address_in_slot [reg PC] $ps $ss $mapper]
}
#
# watch_in_slot
#
set_help_text watch_in_slot \
{Test whether the address watched is inside a certain slot.
To be used only to set watchpoints in specific slots.}
proc watch_in_slot {ps {ss "X"} {mapper "X"}} {
return [address_in_slot $::wp_last_address $ps $ss $mapper]
}
#
# helper proc for pc_in_slot and watch_in_slot
#
set_help_text address_in_slot \
{Test whether an address is inside a certain slot.
Typically used by pc_in_slot and watch_in_slot.}
proc address_in_slot {addr ps {ss "X"} {block "X"}} {
# get current page and slots
set page [expr {$addr >> 14}]
lassign [get_selected_slot $page] pc_ps pc_ss
# check primary and secondary slot
if {($ps ne "X") && ($pc_ps != $ps)} {return 0}
if {($ss ne "X") && ($pc_ss ne "X") && ($pc_ss != $ss)} {return 0}
# need to check block?
if {$block eq "X"} {return true}
# first (try to) check memory mapper
if {$pc_ss eq "X"} {set pc_ss 0}
set mapper_size [get_mapper_size $pc_ps $pc_ss]
if {$mapper_size != 0} {
set pc_block [debug read "MapperIO" $page]
return [expr {$block == ($pc_block & ($mapper_size - 1))}]
}
# next (try to) check rom mapper
set block_size [get_block_size $pc_ps $pc_ss $page]
if {$block_size != 0} {
set device_name [lindex [machine_info slot $pc_ps $pc_ss $page] 0]
# note: I'm assuming that if get_block_size returns a non-zero
# value, then the "romblocks" debuggable always exixts.
# Is that correct?
set pc_block [debug read "$device_name romblocks" $addr]
return [expr {$block == $pc_block}]
}
# no mapper present, ok (or should we check block==0 ?)
return 1
}
#
# slotmap
#
set_help_text slotmap \
{Gives an overview of the devices in the different slots.}
proc slotmap_helper {ps ss} {
set result ""
for {set page 0} {$page < 4} {incr page} {
set device_list [machine_info slot $ps $ss $page]
# This 'if' introduces a parsing ambiguity (list of elements
# without embedded spaces versus single element with embedded
# spaces) though usually this looks nicer.
# Though this means the output of this script should not be
# further parsed in scripts.
if {[llength $device_list] == 1} {
set name [lindex $device_list 0]
} else {
set name $device_list
}
append result [format "%04X: %s\n" [expr {$page * 0x4000}] $name]
}
return $result
}
proc slotmap_name {ps ss} {
set t [list $ps $ss]
foreach slot [machine_info external_slot] {
if {[lrange [machine_info external_slot $slot] 0 1] eq $t} {
return " (${slot})"
}
}
return ""
}
proc slotmap {} {
set result ""
for {set ps 0} {$ps < 4} {incr ps} {
if {[machine_info issubslotted $ps]} {
for {set ss 0} {$ss < 4} {incr ss} {
append result "slot $ps.$ss[slotmap_name $ps $ss]:\n"
append result [slotmap_helper $ps $ss]
}
} else {
append result "slot $ps[slotmap_name $ps X]:\n"
append result [slotmap_helper $ps 0]
}
}
return $result
}
#
# iomap
#
set_help_text iomap \
{Gives an overview of the devices connected to the different I/O ports.}
proc iomap_helper {prefix begin end name} {
if {$name eq "empty"} {return ""}
set result [format "port %02X" $begin]
if {$begin == ($end - 1)} {
append result ": "
} else {
append result [format "-%02X:" [expr {$end - 1}]]
}
append result " $prefix $name\n"
}
proc iomap {} {
set result ""
set port 0
while {$port < 256} {
set in [machine_info input_port $port]
set out [machine_info output_port $port]
set end [expr {$port + 1}]
while {($end < 256) &&
($in eq [machine_info input_port $end]) &&
($out eq [machine_info output_port $end])} {
incr end
}
if {$in eq $out} {
append result [iomap_helper "I/O" $port $end $in ]
} else {
append result [iomap_helper "I " $port $end $in ]
append result [iomap_helper " O" $port $end $out]
}
set port $end
}
return $result
}
namespace export get_selected_slot
namespace export slotselect
namespace export get_mapper_size
namespace export pc_in_slot
namespace export watch_in_slot
namespace export address_in_slot
namespace export slotmap
namespace export iomap
} ;# namespace slot
namespace import slot::*
|