_vdp.tcl 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. namespace eval vdp {
  2. set_help_text getcolor \
  3. {Return the current V99x8 palette settings for the given color index (0-15).
  4. The result is format as RGB, with each component in the range 0-7.
  5. }
  6. proc getcolor {index} {
  7. set rb [debug read "VDP palette" [expr {2 * $index}]]
  8. set g [debug read "VDP palette" [expr {2 * $index + 1}]]
  9. format "%03x" [expr {(($rb * 16) & 0x700) + (($g * 16) & 0x070) + ($rb & 0x007)}]
  10. }
  11. set_help_text setcolor \
  12. {Change the V99x8 palette settings. See also getcolor.
  13. usage:
  14. setcolor <index> <r><g><b>
  15. <index> 0-15
  16. <r><g><b> 0-7
  17. }
  18. proc setcolor {index rgb} {
  19. if {[catch {
  20. if {[string length $rgb] != 3} error
  21. set r [string index $rgb 0]
  22. set g [string index $rgb 1]
  23. set b [string index $rgb 2]
  24. if {($index < 0) || ($index > 15)} error
  25. if {($r > 7) || ($g > 7) || ($b > 7)} error
  26. debug write "VDP palette" [expr {$index * 2}] [expr {$r * 16 + $b}]
  27. debug write "VDP palette" [expr {$index * 2 + 1}] $g
  28. }]} {
  29. error "Usage: setcolor <index> <rgb>\n index 0..15\n r,g,b 0..7"
  30. }
  31. }
  32. proc format_table {entries columns frmt sep func} {
  33. set result ""
  34. set rows [expr {($entries + $columns - 1) / $columns}]
  35. for {set row 0} {$row < $rows} {incr row} {
  36. set line ""
  37. for {set col 0} {$col < $columns} {incr col} {
  38. set index [expr {$row + ($col * $rows)}]
  39. if {$index < $entries} {
  40. append line [format $frmt $index [$func $index]] $sep
  41. }
  42. }
  43. append result "${line}\n"
  44. }
  45. return $result
  46. }
  47. set_help_text vdpreg "Read or write a V99x8 register."
  48. proc vdpreg {reg {value ""}} {
  49. if {$value eq ""} {
  50. debug read "VDP regs" $reg
  51. } else {
  52. debug write "VDP regs" $reg $value
  53. }
  54. }
  55. set_help_text vdpregs "Gives an overview of the V99x8 registers."
  56. proc vdpregs {} {
  57. format_table 32 4 "%2d : 0x%02x" " " vdpreg
  58. }
  59. set_help_text v9990reg "Read or write a V9990 register."
  60. proc v9990reg {reg {value ""}} {
  61. if {$value eq ""} {
  62. debug read "Sunrise GFX9000 regs" $reg
  63. } else {
  64. debug write "Sunrise GFX9000 regs" $reg $value
  65. }
  66. }
  67. set_help_text v9990regs "Gives an overview of the V9990 registers."
  68. proc v9990regs {} {
  69. format_table 55 5 "%2d : 0x%02x" " " v9990reg
  70. }
  71. set_help_text palette "Gives an overview of the V99x8 palette registers."
  72. proc palette {} {
  73. format_table 16 4 "%x:%s" " " getcolor
  74. }
  75. proc val2bin val {
  76. set binRep [binary format c $val]
  77. binary scan $binRep B* binStr
  78. return $binStr
  79. }
  80. variable mode_lookup
  81. set mode_lookup(00000000) 1;# Screen 1
  82. set mode_lookup(00000001) "TEXT40";# Screen 0 (WIDTH 40)
  83. set mode_lookup(00000010) 3;# Screen 3
  84. set mode_lookup(00000100) 2;# Screen 2
  85. set mode_lookup(00001000) 4;# Screen 4
  86. set mode_lookup(00001001) "TEXT80";# Screen 0 (WIDTH 80)
  87. set mode_lookup(00001100) 5;# Screen 5
  88. set mode_lookup(00010000) 6;# Screen 6
  89. set mode_lookup(00010100) 7;# Screen 7
  90. set mode_lookup(00011100) 8;# Screen 8
  91. set_help_text get_screen_mode_number "Decodes the current screen mode from the VDP registers (as would be used in the BASIC SCREEN command)"
  92. proc get_screen_mode_number {} {
  93. set mode [get_screen_mode]
  94. if {[string range $mode 0 3] eq "TEXT"} {
  95. return 0
  96. } elseif {$mode eq "invalid"} {
  97. return -1
  98. }
  99. return $mode
  100. }
  101. set_help_text get_screen_mode "Decodes the current screen mode from the VDP registers (and returns it as a string)."
  102. proc get_screen_mode {} {
  103. variable mode_lookup
  104. set val [expr {(([vdpreg 0] & 14) << 1) | (([vdpreg 1] & 8) >> 2) | (([vdpreg 1] & 16) >> 4)}]
  105. if {[catch {set mode $mode_lookup([val2bin $val])}]} {
  106. return "invalid"
  107. }
  108. if {(($mode == 8) || ($mode == 7)) && ([vdpreg 25] & 8)} {
  109. set mode [expr {([vdpreg 25] & 16) ? 11 : 12}]
  110. }
  111. return $mode
  112. }
  113. set_help_text vpeek \
  114. {Similar to the BASIC vpeek command, read a byte from the video RAM.
  115. This command has the same view on the VRAM as the programmer sees (as opposed
  116. to the physical VRAM content):
  117. - The whole 128kB address space is visible, if the machine has less VRAM
  118. then some parts will either be mirrored or unmapped.
  119. - Depending on the current screen mode, the VRAM addressing is interleaved
  120. or not. This command follows that addressing scheme (IOW, normally you
  121. don't have to care).
  122. See also the 'vpoke' command.
  123. }
  124. proc vpeek {addr} {
  125. debug read VRAM $addr
  126. }
  127. set_help_text vpoke \
  128. {Similar to the BASIC vpoke command, write a byte to the video RAM.
  129. See the 'vpeek' command for more info about the VRAM address space.
  130. }
  131. proc vpoke {addr val} {
  132. debug write VRAM $addr $val
  133. }
  134. namespace export getcolor
  135. namespace export setcolor
  136. namespace export get_screen_mode
  137. namespace export get_screen_mode_number
  138. namespace export vdpreg
  139. namespace export vdpregs
  140. namespace export v9990regs
  141. namespace export vpeek
  142. namespace export vpoke
  143. namespace export palette
  144. } ;# namespace vdp
  145. namespace import vdp::*