mirror of
https://github.com/MutableLoss/6502SimDesktop.git
synced 2024-11-28 07:49:17 +00:00
1195 lines
39 KiB
NASM
1195 lines
39 KiB
NASM
.importonce
|
|
|
|
// The MIT License (MIT)
|
|
//
|
|
// Copyright (c) 2015 Michał Taszycki
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
// copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
|
|
.const _64SPEC_VERSION_MAJOR = 0
|
|
.const _64SPEC_VERSION_MINOR = 5
|
|
.const _64SPEC_VERSION_PATCH = 0
|
|
|
|
.function _64spec_version() {
|
|
.return "" + _64SPEC_VERSION_MAJOR + '.' + _64SPEC_VERSION_MINOR + '.' + _64SPEC_VERSION_PATCH
|
|
}
|
|
|
|
.const _TEXT_COLOR = $0286
|
|
.const _BORDER = $d020
|
|
.const _BACKGROUND = $d021
|
|
.const _CHROUT = $ffd2
|
|
.const _CHKOUT = $FFC9
|
|
.const _PLOT = $fff0
|
|
.const _SETLFS = $FFBA
|
|
.const _OPEN = $FFC0
|
|
.const _CLOSE = $FFC3
|
|
.const _SETNAM = $FFBD
|
|
.const _CLRCHN = $FFCC
|
|
.const _CLRSCR = $e544
|
|
.const _PRINTWORD = $bdcd
|
|
.const _CR=13
|
|
.const _CLS = 147
|
|
.const _UPPERCASE = 142
|
|
.const _LOWERCASE = 14
|
|
|
|
|
|
.struct _64SPEC_CONFIG {
|
|
print_header,
|
|
clear_screen_at_initialization,
|
|
change_character_set,
|
|
on_exit,
|
|
success_color,
|
|
failure_color,
|
|
change_text_color,
|
|
change_text_color_on_final_result,
|
|
change_text_color_on_immediate_result,
|
|
text_color,
|
|
revert_to_initial_text_color,
|
|
change_background_color,
|
|
change_background_color_on_final_result,
|
|
background_color,
|
|
change_border_color,
|
|
border_color,
|
|
change_border_color_on_final_result,
|
|
print_immediate_result,
|
|
immediate_result_success_character,
|
|
immediate_result_failure_character,
|
|
print_final_results,
|
|
write_final_results_to_file,
|
|
result_file_name,
|
|
assertion_passed_subroutine,
|
|
assertion_failed_subroutine,
|
|
result_all_passed_message,
|
|
result_some_passed_message,
|
|
result_all_failed_message,
|
|
print_configuration,
|
|
print_command_line_options,
|
|
print_context_description,
|
|
print_example_description,
|
|
change_context_description_text_color,
|
|
change_example_description_text_color,
|
|
print_context_results,
|
|
print_example_results,
|
|
|
|
_use_custom_result_all_passed_message,
|
|
_use_custom_result_some_passed_message,
|
|
_use_custom_result_all_failed_message,
|
|
_use_custom_assertion_passed_subroutine,
|
|
_use_custom_assertion_failed_subroutine
|
|
}
|
|
|
|
// Default configuration
|
|
.const _64SPEC = _64SPEC_CONFIG()
|
|
.eval config_64spec("print_header", true)
|
|
.eval config_64spec("clear_screen_at_initialization", true)
|
|
.eval config_64spec("change_character_set", "lowercase")
|
|
.eval config_64spec("on_exit", "rts")
|
|
|
|
.eval config_64spec("success_color", GREEN)
|
|
.eval config_64spec("failure_color", RED)
|
|
|
|
.eval config_64spec("change_text_color", true)
|
|
.eval config_64spec("change_text_color_on_immediate_result", true)
|
|
.eval config_64spec("change_text_color_on_final_result", true)
|
|
.eval config_64spec("text_color", DARK_GRAY)
|
|
.eval config_64spec("revert_to_initial_text_color", false)
|
|
|
|
.eval config_64spec("change_background_color", true)
|
|
.eval config_64spec("change_background_color_on_final_result", false)
|
|
.eval config_64spec("background_color", BLACK)
|
|
|
|
.eval config_64spec("change_border_color", true)
|
|
.eval config_64spec("change_border_color_on_final_result", true)
|
|
.eval config_64spec("border_color", BLACK)
|
|
|
|
.eval config_64spec("print_context_description", true)
|
|
.eval config_64spec("print_example_description", true)
|
|
// TODO: Fix color printing when screen scrolls, and change defaults to true.
|
|
.eval config_64spec("change_context_description_text_color", false)
|
|
.eval config_64spec("change_example_description_text_color", false)
|
|
.eval config_64spec("print_context_results", false)
|
|
.eval config_64spec("print_example_results", false)
|
|
|
|
.eval config_64spec("print_immediate_result", true)
|
|
.eval config_64spec("immediate_result_success_character", "default")
|
|
.eval config_64spec("immediate_result_failure_character", "default")
|
|
.eval config_64spec("print_final_results", true)
|
|
.eval config_64spec("write_final_results_to_file", false)
|
|
.eval config_64spec("result_file_name", "result.txt")
|
|
|
|
|
|
.eval config_64spec("print_configuration", false)
|
|
.eval config_64spec("print_command_line_options", false)
|
|
|
|
// Overridable addresses. Set at initialization time.
|
|
.eval config_64spec("assertion_passed_subroutine", "default")
|
|
.eval config_64spec("assertion_failed_subroutine", "default")
|
|
.eval config_64spec("result_all_passed_message", "default")
|
|
.eval config_64spec("result_some_passed_message", "default")
|
|
.eval config_64spec("result_all_failed_message", "default")
|
|
|
|
// Custom memory markers.
|
|
// Some labels cannot be resolved in the first pass and we can't use them in .if statements.
|
|
// Therefore additional boolean variables are used to signify if user customized an address.
|
|
.eval _64SPEC.set("_use_custom_result_all_passed_message", false)
|
|
.eval _64SPEC.set("_use_custom_result_some_passed_message", false)
|
|
.eval _64SPEC.set("_use_custom_result_all_failed_message", false)
|
|
.eval _64SPEC.set("_use_custom_assertion_passed_subroutine", false)
|
|
.eval _64SPEC.set("_use_custom_assertion_failed_subroutine", false)
|
|
|
|
.function config_64spec(key, value) {
|
|
.if (validate_boolean_option("print_header", key, value)) .return
|
|
.if (validate_boolean_option("clear_screen_at_initialization", key, value)) .return
|
|
.if (validate_boolean_option("change_text_color", key, value)) .return
|
|
.if (validate_boolean_option("change_text_color_on_immediate_result", key, value)) .return
|
|
.if (validate_boolean_option("change_text_color_on_final_result", key, value)) .return
|
|
.if (validate_boolean_option("revert_to_initial_text_color", key, value)) .return
|
|
.if (validate_boolean_option("change_background_color", key, value)) .return
|
|
.if (validate_boolean_option("change_background_color_on_final_result", key, value)) .return
|
|
.if (validate_boolean_option("change_border_color", key, value)) .return
|
|
.if (validate_boolean_option("change_border_color_on_final_result", key, value)) .return
|
|
.if (validate_boolean_option("print_immediate_result", key, value)) .return
|
|
.if (validate_boolean_option("print_final_results", key, value)) .return
|
|
.if (validate_boolean_option("write_final_results_to_file", key, value)) .return
|
|
.if (validate_boolean_option("print_configuration", key, value)) .return
|
|
.if (validate_boolean_option("print_command_line_options", key, value)) .return
|
|
.if (validate_boolean_option("print_context_description", key, value)) .return
|
|
.if (validate_boolean_option("print_example_description", key, value)) .return
|
|
.if (validate_boolean_option("change_context_description_text_color", key, value)) .return
|
|
.if (validate_boolean_option("change_example_description_text_color", key, value)) .return
|
|
.if (validate_boolean_option("print_context_results", key, value)) .return
|
|
.if (validate_boolean_option("print_example_results", key, value)) .return
|
|
|
|
.if (validate_color_option("success_color", key, value)) .return
|
|
.if (validate_color_option("failure_color", key, value)) .return
|
|
.if (validate_color_option("text_color", key, value)) .return
|
|
.if (validate_color_option("background_color", key, value)) .return
|
|
.if (validate_color_option("border_color", key, value)) .return
|
|
|
|
.if (validate_character_option("immediate_result_success_character", key, value)) .return
|
|
.if (validate_character_option("immediate_result_failure_character", key, value)) .return
|
|
|
|
.if (validate_non_empty_string_option("result_file_name", key, value)) .return
|
|
|
|
.if (validate_set_option("change_character_set", List().add(
|
|
_64SPEC_SET_OPTION("\"lowercase\"", "lowercase"),
|
|
_64SPEC_SET_OPTION("\"uppercase\"", "uppercase"),
|
|
_64SPEC_SET_OPTION("false", false)
|
|
), key, value)) .return
|
|
|
|
.if (validate_set_option("on_exit", List().add(
|
|
_64SPEC_SET_OPTION("\"rts\"", "rts"),
|
|
_64SPEC_SET_OPTION("\"loop\"", "loop"),
|
|
_64SPEC_SET_OPTION("\"jam\"", "jam")
|
|
), key, value)) .return
|
|
|
|
.if (mark_custom_memory_address_option("assertion_passed_subroutine", key, value)) .return
|
|
.if (mark_custom_memory_address_option("assertion_failed_subroutine", key, value)) .return
|
|
.if (mark_custom_memory_address_option("result_all_passed_message", key, value)) .return
|
|
.if (mark_custom_memory_address_option("result_some_passed_message", key, value)) .return
|
|
.if (mark_custom_memory_address_option("result_all_failed_message", key, value)) .return
|
|
|
|
.error "Unrecognized _64SPEC configuration option - \"" + key + "\""
|
|
}
|
|
.function mark_custom_memory_address_option(expected_key, key, value) {
|
|
.if (key != expected_key) .return false
|
|
|
|
.eval _64SPEC.set("_use_custom_" + expected_key, true)
|
|
.eval _64SPEC.set(key, value)
|
|
.return true
|
|
}
|
|
.function validate_color_option(expected_key, key, value) {
|
|
.if (key != expected_key) .return false
|
|
|
|
.if(value < 0 || value > 15) {
|
|
.error "_64SPEC configuration option - \"" + expected_key + "\" has to be a valid color index in a range [0..15]."
|
|
}
|
|
|
|
.eval _64SPEC.set(key, value)
|
|
.return true
|
|
}
|
|
.function validate_boolean_option(expected_key, key, value) {
|
|
.if (key != expected_key) .return false
|
|
|
|
.if (value != true && value != false) {
|
|
.error "_64SPEC configuration option - \"" + expected_key + "\" has to be either be true or false."
|
|
}
|
|
|
|
.eval _64SPEC.set(key, value)
|
|
.return true
|
|
}
|
|
|
|
.function validate_non_empty_string_option(expected_key, key, value) {
|
|
.if (key != expected_key) .return false
|
|
|
|
.if (value == "") {
|
|
.error "_64SPEC configuration option - \"" + expected_key + "\" cannot be an empty string."
|
|
}
|
|
|
|
.eval _64SPEC.set(key, value)
|
|
.return true
|
|
}
|
|
|
|
.function validate_character_option(expected_key, key, value) {
|
|
.if (key != expected_key) .return false
|
|
|
|
.if (value != "default" && [value < 0 || value > 255]) {
|
|
.error "_64SPEC configuration option - \"" + expected_key + "\" has to be a one byte value representing PETSCII character or \"default\"."
|
|
}
|
|
|
|
.eval _64SPEC.set(key, value)
|
|
.return true
|
|
}
|
|
.struct _64SPEC_SET_OPTION {name, value}
|
|
.function validate_set_option(expected_key, allowed_values, key, value) {
|
|
.if (key != expected_key) .return false
|
|
|
|
.var options_string = ""
|
|
.for (var i = 0; i < allowed_values.size(); i++) {
|
|
.eval options_string += allowed_values.get(i).name
|
|
.if (i < allowed_values.size() - 1) {
|
|
.eval options_string += ", "
|
|
}
|
|
.if (value == allowed_values.get(i).value) {
|
|
.eval _64SPEC.set(key, value)
|
|
.return true
|
|
}
|
|
}
|
|
|
|
.error "_64SPEC configuration option - \"" + expected_key + "\" has to be a one of: " + options_string
|
|
}
|
|
|
|
.macro init_spec() {
|
|
|
|
.if (cmdLineVars.containsKey("on_exit")) {
|
|
.eval _64SPEC.set("on_exit", cmdLineVars.get("on_exit"))
|
|
}
|
|
.if (cmdLineVars.containsKey("write_final_results_to_file")) {
|
|
.eval _64SPEC.set("write_final_results_to_file", cmdLineVars.get("write_final_results_to_file").asBoolean())
|
|
}
|
|
.if (cmdLineVars.containsKey("result_file_name")) {
|
|
.eval _64SPEC.set("result_file_name", cmdLineVars.get("result_file_name"))
|
|
}
|
|
|
|
.if (_64SPEC.immediate_result_failure_character == "default") {
|
|
.eval _64SPEC.set("immediate_result_failure_character", [_64SPEC.change_character_set == "lowercase"] ? _64spec_scr_to_pet('x') : _64spec_scr_to_pet('x'))
|
|
}
|
|
.if (_64SPEC.immediate_result_success_character == "default") {
|
|
.eval _64SPEC.set("immediate_result_success_character", [_64SPEC.change_character_set == "lowercase"] ? _64spec_scr_to_pet('.') : _64spec_scr_to_pet('.'))
|
|
}
|
|
|
|
.if (_64SPEC.print_configuration) {
|
|
.print "64Spec Configuration:"
|
|
.for (var i = 0;i < _64SPEC.getNoOfFields(); i++) {
|
|
.print " " + _64SPEC.getFieldNames().get(i) + " = " +_64SPEC.get(i)
|
|
}
|
|
}
|
|
|
|
.if (_64SPEC.print_command_line_options) {
|
|
.print "Command Line Options:"
|
|
.for (var i = 0;i < cmdLineVars.keys().size(); i++) {
|
|
.var key = cmdLineVars.keys().get(i)
|
|
.print " " + key + " = " + cmdLineVars.get(key)
|
|
}
|
|
}
|
|
|
|
:BasicUpstart2(tests_init)
|
|
|
|
.pc = * "Tests Data"
|
|
_version_major:
|
|
.byte _64SPEC_VERSION_MAJOR
|
|
_version_minor:
|
|
.byte _64SPEC_VERSION_MINOR
|
|
_version_patch:
|
|
.byte _64SPEC_VERSION_PATCH
|
|
_total_assertions_count:
|
|
.word 0
|
|
_passed_assertions_count:
|
|
.word 0
|
|
_final_tests_result:
|
|
.word 0
|
|
_stored_a:
|
|
.byte 0
|
|
_stored_x:
|
|
.byte 0
|
|
_stored_y:
|
|
.byte 0
|
|
_stored_p:
|
|
.byte 0
|
|
_initial_text_color:
|
|
.if (_64SPEC.change_text_color && _64SPEC.revert_to_initial_text_color) {
|
|
.byte 0
|
|
}
|
|
_header:
|
|
.if (_64SPEC.print_header) {
|
|
.var lines = List()
|
|
.if (_64SPEC.change_character_set == "lowercase") {
|
|
.eval lines.add("****** 64spec v" + _64spec_version() + " ******")
|
|
.eval lines.add("Testing Framework by Michal Taszycki")
|
|
.eval lines.add("Docs at http://64bites.com/64spec")
|
|
} else {
|
|
.eval lines.add("****** 64spec v" + _64spec_version() + " ******")
|
|
.eval lines.add("testing framework by michal taszycki")
|
|
.eval lines.add("docs at http://64bites.com/64spec")
|
|
}
|
|
.byte _CR
|
|
.for (var i = 0; i < lines.size(); i++) {
|
|
.fill [40 - lines.get(i).size()] / 2, ' '
|
|
:_64spec_pet_text(lines.get(i))
|
|
.byte _CR
|
|
.byte _CR
|
|
}
|
|
.byte 0
|
|
}
|
|
|
|
.if(!_64SPEC._use_custom_result_all_failed_message) {
|
|
.eval _64SPEC.set("result_all_failed_message", *)
|
|
.if (_64SPEC.change_character_set == "lowercase") {
|
|
:_64spec_pet_text("All Tests FAILED: ")
|
|
} else {
|
|
:_64spec_pet_text("all tests failed: ")
|
|
}
|
|
.byte 0
|
|
}
|
|
.if(!_64SPEC._use_custom_result_some_passed_message) {
|
|
.eval _64SPEC.set("result_some_passed_message", *)
|
|
.if (_64SPEC.change_character_set == "lowercase") {
|
|
:_64spec_pet_text("Some tests PASSED: ")
|
|
} else {
|
|
:_64spec_pet_text("some tests passed: ")
|
|
}
|
|
.byte 0
|
|
}
|
|
.if(!_64SPEC._use_custom_result_all_passed_message) {
|
|
.eval _64SPEC.set("result_all_passed_message", *)
|
|
.if (_64SPEC.change_character_set == "lowercase") {
|
|
:_64spec_pet_text("All tests PASSED: ")
|
|
} else {
|
|
:_64spec_pet_text("all tests passed: ")
|
|
}
|
|
.byte 0
|
|
}
|
|
_last_context:
|
|
.if (_64SPEC.print_context_description) {
|
|
.word 0 // text pointer
|
|
.word 0 // cursor position
|
|
.word 0 // total assertions count
|
|
.word 0 // passed assertions count
|
|
.byte 0 // tests result
|
|
}
|
|
_last_example:
|
|
.if (_64SPEC.print_example_description) {
|
|
.word 0 // text pointer
|
|
.word 0 // cursor position
|
|
.word 0 // total assertions count
|
|
.word 0 // passed assertions count
|
|
.byte 0 // tests result
|
|
}
|
|
_description_data:
|
|
.if (_64SPEC.print_context_description || _64SPEC.print_example_description) {
|
|
.word 0 // cursor position
|
|
.byte 0 // flags - 7 cleared - first context, 6 cleared - first example
|
|
}
|
|
|
|
.pc = * "Tests Subroutines"
|
|
.if(!_64SPEC._use_custom_assertion_passed_subroutine) {
|
|
.eval _64SPEC.set("assertion_passed_subroutine", *)
|
|
:_assertion_passed()
|
|
rts
|
|
}
|
|
.if(!_64SPEC._use_custom_assertion_failed_subroutine) {
|
|
.eval _64SPEC.set("assertion_failed_subroutine", *)
|
|
:_assertion_failed()
|
|
rts
|
|
}
|
|
_print_string:
|
|
:_print_string($ffff)
|
|
rts
|
|
.pc = * "Test Initialization"
|
|
tests_init:
|
|
.if (_64SPEC.clear_screen_at_initialization) {
|
|
:_print_char #_CLS
|
|
}
|
|
.if (_64SPEC.change_character_set != false) {
|
|
:_print_char #[[_64SPEC.change_character_set == "lowercase"] ? _LOWERCASE : _UPPERCASE]
|
|
}
|
|
.if (_64SPEC.change_text_color && _64SPEC.revert_to_initial_text_color) {
|
|
:_64spec_mov _TEXT_COLOR; _initial_text_color
|
|
}
|
|
:_set_text_color #_64SPEC.text_color
|
|
.if (_64SPEC.change_background_color) {
|
|
:_64spec_mov #_64SPEC.background_color; _BACKGROUND
|
|
}
|
|
.if (_64SPEC.change_border_color) {
|
|
:_64spec_mov #_64SPEC.border_color; _BORDER
|
|
}
|
|
.if (_64SPEC.print_header) {
|
|
:_print_string #sfspec._header
|
|
}
|
|
:_reset_tests_result(sfspec._total_assertions_count)
|
|
|
|
.pc = * "Specification"
|
|
specification:
|
|
}
|
|
|
|
.macro finish_spec() {
|
|
.pc = * "Spec Results Rendering"
|
|
:_finalize_last_context()
|
|
:_finalize_last_example()
|
|
:render_results()
|
|
.if (_64SPEC.revert_to_initial_text_color) {
|
|
:_set_text_color sfspec._initial_text_color
|
|
} else {
|
|
:_set_text_color #_64SPEC.text_color
|
|
}
|
|
.if (_64SPEC.on_exit == "rts") {
|
|
rts
|
|
} else .if (_64SPEC.on_exit == "loop") {
|
|
end:
|
|
jmp end
|
|
} else /* jam */ {
|
|
.byte $02
|
|
}
|
|
}
|
|
|
|
.macro _assertion_failed() {
|
|
:_64spec_inc16 sfspec._total_assertions_count
|
|
.if (_64SPEC.print_context_description) {
|
|
:_64spec_inc16 sfspec._last_context + 4
|
|
}
|
|
.if (_64SPEC.print_example_description) {
|
|
:_64spec_inc16 sfspec._last_example + 4
|
|
}
|
|
.if (_64SPEC.print_immediate_result) {
|
|
.if (_64SPEC.change_text_color_on_immediate_result) {
|
|
:_set_text_color #_64SPEC.failure_color
|
|
}
|
|
:_print_char #_64SPEC.immediate_result_failure_character
|
|
}
|
|
}
|
|
|
|
.macro _assertion_passed() {
|
|
:_64spec_inc16 sfspec._passed_assertions_count
|
|
:_64spec_inc16 sfspec._total_assertions_count
|
|
.if (_64SPEC.print_context_description) {
|
|
:_64spec_inc16 sfspec._last_context + 4
|
|
:_64spec_inc16 sfspec._last_context + 6
|
|
}
|
|
.if (_64SPEC.print_example_description) {
|
|
:_64spec_inc16 sfspec._last_example + 4
|
|
:_64spec_inc16 sfspec._last_example + 6
|
|
}
|
|
.if (_64SPEC.print_immediate_result) {
|
|
.if (_64SPEC.change_text_color_on_immediate_result) {
|
|
:_set_text_color #_64SPEC.success_color
|
|
}
|
|
:_print_char #_64SPEC.immediate_result_success_character
|
|
}
|
|
}
|
|
.macro _reset_tests_result(base_address) {
|
|
.var total_assertions_count = base_address
|
|
.var passed_assertions_count = base_address + 2
|
|
:_64spec_mov16 #$0000; total_assertions_count
|
|
:_64spec_mov16 #$0000; passed_assertions_count
|
|
}
|
|
.macro _calculate_tests_result(base_address) {
|
|
.var total_assertions_count = base_address
|
|
.var passed_assertions_count = base_address + 2
|
|
.var final_tests_result = base_address + 4
|
|
|
|
lda total_assertions_count
|
|
cmp passed_assertions_count
|
|
bne !fail+
|
|
lda total_assertions_count + 1
|
|
cmp passed_assertions_count + 1
|
|
bne !fail+
|
|
!pass:
|
|
// We are "overflowing" with success
|
|
lda #%01000000
|
|
sta final_tests_result
|
|
jmp !end+
|
|
!fail:
|
|
lda passed_assertions_count
|
|
bne !incomplete_fail+
|
|
lda passed_assertions_count + 1
|
|
bne !incomplete_fail+
|
|
!complete_fail:
|
|
// We are "not overflowing" with success
|
|
lda #%00000000
|
|
sta final_tests_result
|
|
jmp !end+
|
|
!incomplete_fail:
|
|
// This is "MInor" failure
|
|
lda #%10000000
|
|
sta final_tests_result
|
|
!end:
|
|
}
|
|
|
|
.macro render_results() {
|
|
:_calculate_tests_result(sfspec._total_assertions_count)
|
|
:_set_screen_colors()
|
|
:_change_text_color_on_final_result()
|
|
.if (_64SPEC.print_final_results) {
|
|
:_print_final_results()
|
|
}
|
|
.if (_64SPEC.write_final_results_to_file) {
|
|
:_write_final_results_to_file()
|
|
}
|
|
}
|
|
|
|
.macro _write_final_results_to_file() {
|
|
:_64spec_open_file_for_writing(_64SPEC.result_file_name, 13)
|
|
:_64spec_set_file_output(13)
|
|
:_print_final_results()
|
|
:_64spec_close_file(13)
|
|
:_64spec_set_screen_output()
|
|
}
|
|
|
|
.macro _change_text_color_on_final_result() {
|
|
.if (_64SPEC.change_text_color_on_final_result) {
|
|
bit sfspec._final_tests_result
|
|
bvs success
|
|
failure:
|
|
:_set_text_color #_64SPEC.failure_color
|
|
jmp end
|
|
success:
|
|
:_set_text_color #_64SPEC.success_color
|
|
end:
|
|
} else {
|
|
:_set_text_color #_64SPEC.text_color
|
|
}
|
|
}
|
|
|
|
.macro _set_screen_colors() {
|
|
.if ([_64SPEC.change_border_color && _64SPEC.change_border_color_on_final_result] || [_64SPEC.change_background_color && _64SPEC.change_background_color_on_final_result]) {
|
|
bit sfspec._final_tests_result
|
|
bvs success
|
|
failure:
|
|
lda #_64SPEC.failure_color
|
|
jmp end
|
|
success:
|
|
lda #_64SPEC.success_color
|
|
end:
|
|
.if (_64SPEC.change_border_color && _64SPEC.change_border_color_on_final_result) {
|
|
sta _BORDER
|
|
}
|
|
.if (_64SPEC.change_background_color && _64SPEC.change_background_color_on_final_result) {
|
|
sta _BACKGROUND
|
|
}
|
|
}
|
|
}
|
|
|
|
.macro _print_result_numbers(base_address) {
|
|
.var total_assertions_count = base_address
|
|
.var passed_assertions_count = base_address + 2
|
|
:_print_char #'('
|
|
:_print_int16 passed_assertions_count
|
|
:_print_char #'/'
|
|
:_print_int16 total_assertions_count
|
|
:_print_char #')'
|
|
:_print_char #_CR
|
|
}
|
|
|
|
.macro _print_final_results() {
|
|
:_print_char #_CR
|
|
bit sfspec._final_tests_result
|
|
bvs success
|
|
bmi partial_failure
|
|
failure:
|
|
:_print_string #_64SPEC.result_all_failed_message
|
|
jmp end
|
|
partial_failure:
|
|
:_print_string #_64SPEC.result_some_passed_message
|
|
jmp end
|
|
success:
|
|
:_print_string #_64SPEC.result_all_passed_message
|
|
end:
|
|
:_print_result_numbers(sfspec._total_assertions_count)
|
|
}
|
|
|
|
// Assertions
|
|
.pseudocommand assert_i_cleared pass_subroutine; fail_subroutine {
|
|
:assert_i_set _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_i_set pass_subroutine; fail_subroutine {
|
|
:assert_p_has_masked_bits_set #%00000100; _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine); _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_d_cleared pass_subroutine; fail_subroutine {
|
|
:assert_d_set _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_d_set pass_subroutine; fail_subroutine {
|
|
:assert_p_has_masked_bits_set #%00001000; _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine); _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_p_has_masked_bits_cleared mask; pass_subroutine; fail_subroutine {
|
|
:assert_masked_bits_cleared sfspec._stored_p; mask; pass_subroutine; fail_subroutine
|
|
}
|
|
.pseudocommand assert_p_has_masked_bits_set mask; pass_subroutine; fail_subroutine {
|
|
:assert_masked_bits_set sfspec._stored_p; mask; pass_subroutine; fail_subroutine
|
|
}
|
|
.pseudocommand assert_masked_bits_cleared actual; mask; pass_subroutine; fail_subroutine {
|
|
:_store_state()
|
|
lda actual
|
|
eor $ff
|
|
and mask
|
|
bne pass_or_fail.fail
|
|
pass_or_fail: :_pass_or_fail pass_subroutine; fail_subroutine
|
|
:_restore_state()
|
|
}
|
|
.pseudocommand assert_masked_bits_set actual; mask; pass_subroutine; fail_subroutine {
|
|
:_store_state()
|
|
lda actual
|
|
and mask
|
|
cmp mask
|
|
bne pass_or_fail.fail
|
|
pass_or_fail: :_pass_or_fail pass_subroutine; fail_subroutine
|
|
:_restore_state()
|
|
}
|
|
.pseudocommand assert_p_equal expected; pass_subroutine; fail_subroutine {
|
|
:assert_equal sfspec._stored_p; expected; pass_subroutine; fail_subroutine
|
|
}
|
|
|
|
.pseudocommand assert_v_cleared pass_subroutine; fail_subroutine {
|
|
:assert_v_set _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_v_set pass_subroutine; fail_subroutine {
|
|
:assert_p_has_masked_bits_set #%01000000; pass_subroutine; fail_subroutine
|
|
}
|
|
|
|
.pseudocommand assert_n_cleared pass_subroutine; fail_subroutine {
|
|
:assert_n_set _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_n_set pass_subroutine; fail_subroutine {
|
|
|
|
:assert_p_has_masked_bits_set #%10000000; pass_subroutine; fail_subroutine
|
|
}
|
|
.pseudocommand assert_c_cleared pass_subroutine; fail_subroutine {
|
|
:assert_c_set _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_c_set pass_subroutine; fail_subroutine {
|
|
:assert_p_has_masked_bits_set #%00000001; pass_subroutine; fail_subroutine
|
|
}
|
|
|
|
.pseudocommand assert_z_cleared pass_subroutine; fail_subroutine {
|
|
:assert_z_set _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_z_set pass_subroutine; fail_subroutine {
|
|
:assert_p_has_masked_bits_set #%00000010; pass_subroutine; fail_subroutine
|
|
}
|
|
|
|
.pseudocommand assert_y_not_zero pass_subroutine; fail_subroutine {
|
|
:assert_y_zero _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_y_zero pass_subroutine; fail_subroutine {
|
|
:assert_y_equal #0; pass_subroutine; fail_subroutine
|
|
}
|
|
|
|
.pseudocommand assert_y_not_equal expected; pass_subroutine; fail_subroutine {
|
|
:assert_y_equal expected; _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_y_equal expected; pass_subroutine; fail_subroutine {
|
|
:assert_equal sfspec._stored_y; expected; pass_subroutine; fail_subroutine
|
|
}
|
|
|
|
.pseudocommand assert_x_not_zero pass_subroutine; fail_subroutine {
|
|
:assert_x_zero _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_x_zero pass_subroutine; fail_subroutine {
|
|
:assert_x_equal #0; pass_subroutine; fail_subroutine
|
|
}
|
|
|
|
.pseudocommand assert_x_not_equal expected; pass_subroutine; fail_subroutine {
|
|
:assert_x_equal expected; _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
.pseudocommand assert_x_equal expected; pass_subroutine; fail_subroutine {
|
|
:assert_equal sfspec._stored_x; expected; pass_subroutine; fail_subroutine
|
|
}
|
|
|
|
.pseudocommand assert_a_not_zero pass_subroutine; fail_subroutine {
|
|
:assert_a_zero _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_a_zero pass_subroutine; fail_subroutine {
|
|
:assert_a_equal #0; pass_subroutine; fail_subroutine
|
|
}
|
|
|
|
.pseudocommand assert_a_not_equal expected; pass_subroutine; fail_subroutine {
|
|
:assert_a_equal expected; _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_a_equal expected; pass_subroutine; fail_subroutine {
|
|
:assert_equal sfspec._stored_a; expected; pass_subroutine; fail_subroutine
|
|
}
|
|
|
|
.pseudocommand assert_not_equal actual; expected; pass_subroutine; fail_subroutine {
|
|
:assert_equal actual; expected;_given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
.pseudocommand assert_not_equal16 actual; expected; pass_subroutine; fail_subroutine {
|
|
:assert_equal16 actual; expected; _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
.pseudocommand assert_not_equal24 actual; expected; pass_subroutine; fail_subroutine {
|
|
:assert_equal24 actual; expected; _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
.pseudocommand assert_not_equal32 actual; expected; pass_subroutine; fail_subroutine {
|
|
:assert_equal32 actual; expected; _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
|
|
.macro assert_bytes_not_equal(bytes_count, actual, expected, pass_subroutine, fail_subroutine) {
|
|
:assert_bytes_equal(bytes_count, actual, expected, _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine), _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine))
|
|
}
|
|
.pseudocommand assert_bytes_not_equal bytes_count; actual; expected; pass_subroutine; fail_subroutine {
|
|
:assert_bytes_equal bytes_count; actual; expected; _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_equal actual; expected; pass_subroutine; fail_subroutine {
|
|
:_assert_equal _bits_to_bytes(8); actual; expected; pass_subroutine; fail_subroutine
|
|
}
|
|
.pseudocommand assert_equal16 actual; expected; pass_subroutine; fail_subroutine {
|
|
:_assert_equal _bits_to_bytes(16); actual; expected; pass_subroutine; fail_subroutine
|
|
}
|
|
.pseudocommand assert_equal24 actual; expected; pass_subroutine; fail_subroutine {
|
|
:_assert_equal _bits_to_bytes(24); actual; expected; pass_subroutine; fail_subroutine
|
|
}
|
|
.pseudocommand assert_equal32 actual; expected; pass_subroutine; fail_subroutine {
|
|
:_assert_equal _bits_to_bytes(32); actual; expected; pass_subroutine; fail_subroutine
|
|
}
|
|
|
|
|
|
.pseudocommand _assert_equal bytes_count; actual; expected; pass_subroutine; fail_subroutine {
|
|
:_store_state()
|
|
.for (var byte_id = 0; byte_id < bytes_count.getValue(); byte_id++) {
|
|
lda _64spec_extract_byte_argument(actual, byte_id)
|
|
cmp _64spec_extract_byte_argument(expected, byte_id)
|
|
bne pass_or_fail.fail
|
|
}
|
|
pass_or_fail: :_pass_or_fail pass_subroutine; fail_subroutine
|
|
:_restore_state()
|
|
}
|
|
|
|
.pseudocommand assert_unsigned_greater_or_equal actual; expected; pass_subroutine; fail_subroutine {
|
|
:assert_unsigned_less actual; expected; _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_unsigned_less actual; expected; pass_subroutine; fail_subroutine {
|
|
:_store_state()
|
|
lda actual
|
|
cmp expected
|
|
bcs pass_or_fail.fail
|
|
pass_or_fail: :_pass_or_fail pass_subroutine; fail_subroutine
|
|
:_restore_state()
|
|
}
|
|
|
|
.pseudocommand assert_unsigned_less_or_equal actual; expected; pass_subroutine; fail_subroutine {
|
|
:assert_unsigned_greater actual; expected; _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine); _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
}
|
|
|
|
.pseudocommand assert_unsigned_greater actual; expected; pass_subroutine; fail_subroutine {
|
|
:_store_state()
|
|
lda actual
|
|
cmp expected
|
|
bcc pass_or_fail.fail
|
|
beq pass_or_fail.fail
|
|
pass_or_fail: :_pass_or_fail pass_subroutine; fail_subroutine
|
|
:_restore_state()
|
|
}
|
|
|
|
.macro _store_state() {
|
|
php
|
|
sta sfspec._stored_a
|
|
stx sfspec._stored_x
|
|
sty sfspec._stored_y
|
|
pla
|
|
sta sfspec._stored_p
|
|
}
|
|
|
|
.macro _restore_state() {
|
|
lda sfspec._stored_p
|
|
pha
|
|
ldy sfspec._stored_y
|
|
ldx sfspec._stored_x
|
|
lda sfspec._stored_a
|
|
plp // restore p
|
|
}
|
|
|
|
.pseudocommand assert_bytes_equal bytes_count; actual; expected; pass_subroutine; fail_subroutine {
|
|
// TODO: remove pages and remainder branches
|
|
.var remainder = mod(bytes_count.getValue(), 256)
|
|
.var offset = bytes_count.getValue() - remainder
|
|
.var pages = offset / 256
|
|
ldy #pages
|
|
beq !end+
|
|
loopy:
|
|
ldx #0
|
|
loopx:
|
|
.label actual_hi = * + 2
|
|
lda actual.getValue(), X
|
|
.label expected_hi = * + 2
|
|
cmp expected.getValue(), X
|
|
bne pass_or_fail.fail
|
|
inx
|
|
bne loopx
|
|
inc actual_hi
|
|
inc expected_hi
|
|
dey
|
|
bne loopy
|
|
!end:
|
|
ldy #remainder
|
|
beq !end+
|
|
ldx #0
|
|
loop:
|
|
lda offset + actual.getValue(), X
|
|
cmp offset + expected.getValue(), X
|
|
bne pass_or_fail.fail
|
|
inx
|
|
cpx #remainder
|
|
bne loop
|
|
!end:
|
|
pass_or_fail: :_pass_or_fail pass_subroutine; fail_subroutine
|
|
}
|
|
.pseudocommand assert_pass pass_subroutine; fail_subroutine {
|
|
:_store_state()
|
|
jsr _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
:_restore_state()
|
|
}
|
|
|
|
.pseudocommand assert_fail pass_subroutine; fail_subroutine {
|
|
:_store_state()
|
|
jsr _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine)
|
|
:_restore_state()
|
|
}
|
|
|
|
.pseudocommand _pass_or_fail pass_subroutine; fail_subroutine {
|
|
pass:
|
|
jsr _given_or_default(pass_subroutine, _64SPEC.assertion_passed_subroutine)
|
|
jmp end
|
|
fail:
|
|
jsr _given_or_default(fail_subroutine, _64SPEC.assertion_failed_subroutine)
|
|
end:
|
|
}
|
|
|
|
.macro describe(subject) {
|
|
.if (_64SPEC.print_context_description) {
|
|
jmp end_text
|
|
text:
|
|
.if (_64SPEC.print_immediate_result || _64SPEC.print_example_description) {
|
|
.byte _CR
|
|
}
|
|
:_64spec_pet_text(subject)
|
|
.byte ' '
|
|
.byte 0
|
|
scoring:
|
|
.text " "
|
|
.byte _CR
|
|
.byte 0
|
|
end_text:
|
|
:_finalize_last_context()
|
|
:_finalize_last_example()
|
|
lda sfspec._description_data + 2
|
|
ora #%10000000
|
|
sta sfspec._description_data + 2
|
|
:_64spec_mov16 #text; sfspec._last_context
|
|
:_64spec_kernal_plot_get sfspec._last_context + 2; sfspec._last_context + 3
|
|
:_set_text_color #_64SPEC.text_color
|
|
:_print_string #text
|
|
:_print_string #scoring
|
|
}
|
|
}
|
|
|
|
.macro _finalize_last_context() {
|
|
.if (_64SPEC.print_context_description ) {
|
|
.if (_64SPEC.change_context_description_text_color) {
|
|
:_calculate_tests_result(sfspec._last_context + 4)
|
|
|
|
bit sfspec._last_context + 8
|
|
bvs pass
|
|
fail:
|
|
:_set_text_color #_64SPEC.failure_color
|
|
jmp end_color
|
|
pass:
|
|
:_set_text_color #_64SPEC.success_color
|
|
end_color:
|
|
}
|
|
.if (_64SPEC.change_context_description_text_color || _64SPEC.print_context_results) {
|
|
bit sfspec._description_data + 2
|
|
bvc end
|
|
:_64spec_kernal_plot_get sfspec._description_data; sfspec._description_data + 1
|
|
:_64spec_kernal_plot_set sfspec._last_context + 2; sfspec._last_context + 3
|
|
:_print_string sfspec._last_context
|
|
:_print_result_numbers(sfspec._last_context + 4)
|
|
|
|
:_64spec_kernal_plot_set sfspec._description_data; sfspec._description_data + 1
|
|
:_reset_tests_result(sfspec._last_context + 4)
|
|
end:
|
|
}
|
|
}
|
|
}
|
|
|
|
.macro it(description) {
|
|
.if (_64SPEC.print_example_description) {
|
|
jmp end_text
|
|
text:
|
|
.if (_64SPEC.print_immediate_result) {
|
|
.byte _CR
|
|
}
|
|
.byte ' '
|
|
:_64spec_pet_text(description)
|
|
.byte ' '
|
|
.byte 0
|
|
scoring:
|
|
.text " "
|
|
.byte _CR
|
|
.byte 0
|
|
end_text:
|
|
:_finalize_last_example()
|
|
lda sfspec._description_data + 2
|
|
ora #%01000000
|
|
sta sfspec._description_data + 2
|
|
:_64spec_mov16 #text; sfspec._last_example
|
|
:_64spec_kernal_plot_get sfspec._last_example + 2; sfspec._last_example + 3
|
|
:_set_text_color #_64SPEC.text_color
|
|
:_print_string #text
|
|
:_print_string #scoring
|
|
}
|
|
}
|
|
|
|
.macro _finalize_last_example() {
|
|
.if (_64SPEC.print_example_description) {
|
|
.if (_64SPEC.change_example_description_text_color) {
|
|
:_calculate_tests_result(sfspec._last_example + 4)
|
|
bit sfspec._last_example + 8
|
|
bvs pass
|
|
fail:
|
|
:_set_text_color #_64SPEC.failure_color
|
|
jmp end_color
|
|
pass:
|
|
:_set_text_color #_64SPEC.success_color
|
|
end_color:
|
|
}
|
|
.if (_64SPEC.change_example_description_text_color || _64SPEC.print_example_results) {
|
|
bit sfspec._description_data + 2
|
|
bvc end
|
|
:_64spec_kernal_plot_get sfspec._description_data; sfspec._description_data + 1
|
|
:_64spec_kernal_plot_set sfspec._last_example + 2; sfspec._last_example + 3
|
|
:_print_string sfspec._last_example
|
|
:_print_result_numbers(sfspec._last_example + 4)
|
|
:_64spec_kernal_plot_set sfspec._description_data; sfspec._description_data + 1
|
|
:_reset_tests_result(sfspec._last_example + 4)
|
|
end:
|
|
}
|
|
}
|
|
}
|
|
|
|
// helper functions
|
|
|
|
.function _given_or_default(given, default) {
|
|
.if (given.getType() == AT_NONE) {
|
|
.return CmdArgument(AT_ABSOLUTE, default)
|
|
} else {
|
|
.return given
|
|
}
|
|
}
|
|
.function _64spec_extract_byte_argument(arg, byte_id) {
|
|
.if (arg.getType()==AT_IMMEDIATE) {
|
|
.return CmdArgument(arg.getType(), _extract_byte(arg.getValue(), byte_id))
|
|
} else {
|
|
.return CmdArgument(arg.getType(), arg.getValue() + byte_id)
|
|
}
|
|
}
|
|
|
|
.function _extract_byte(value, byte_id) {
|
|
.var bits = _bytes_to_bits(byte_id)
|
|
.eval value = value >> bits
|
|
.return value & $ff
|
|
}
|
|
.function _bytes_to_bits(bytes) {
|
|
.return bytes * 8
|
|
}
|
|
|
|
.function _bits_to_bytes(bits) {
|
|
.return bits / 8
|
|
}
|
|
|
|
.pseudocommand _print_string string {
|
|
:_64spec_mov16 string; sfspec._print_string.string_address
|
|
jsr sfspec._print_string
|
|
}
|
|
.macro _print_string(string) {
|
|
ldy #0
|
|
loop:
|
|
.label string_address = * + 1
|
|
lda string, Y
|
|
beq end
|
|
jsr _CHROUT
|
|
iny
|
|
jmp loop
|
|
end:
|
|
}
|
|
|
|
.pseudocommand _print_char char {
|
|
lda char
|
|
jsr _CHROUT
|
|
}
|
|
|
|
.pseudocommand _print_int8 value {
|
|
ldx value
|
|
lda #0
|
|
jsr _PRINTWORD
|
|
}
|
|
|
|
.pseudocommand _print_int16 value {
|
|
ldx _64spec_extract_byte_argument(value, 0)
|
|
lda _64spec_extract_byte_argument(value, 1)
|
|
jsr _PRINTWORD
|
|
}
|
|
|
|
|
|
.pseudocommand _set_text_color color {
|
|
.if (_64SPEC.change_text_color) {
|
|
:_64spec_mov color; _TEXT_COLOR
|
|
}
|
|
}
|
|
|
|
.pseudocommand _64spec_mov source; destination {
|
|
:_64spec__mov _bits_to_bytes(8); source; destination
|
|
}
|
|
|
|
.pseudocommand _64spec_mov16 source; destination {
|
|
:_64spec__mov _bits_to_bytes(16); source; destination
|
|
}
|
|
|
|
.pseudocommand _64spec__mov bytes_count; source; destination {
|
|
.for (var i = 0; i < bytes_count.getValue(); i++) {
|
|
lda _64spec_extract_byte_argument(source, i)
|
|
sta _64spec_extract_byte_argument(destination, i)
|
|
}
|
|
}
|
|
|
|
.pseudocommand _64spec_inc16 arg {
|
|
:_64spec__inc _bits_to_bytes(16); arg
|
|
}
|
|
|
|
.pseudocommand _64spec__inc bytes;arg {
|
|
.for (var byte_id = 0;byte_id < bytes.getValue(); byte_id++) {
|
|
inc _64spec_extract_byte_argument(arg, byte_id)
|
|
bne end
|
|
}
|
|
end:
|
|
}
|
|
.macro _64spec_pet_text(string) {
|
|
.fill string.size(), _64spec_scr_to_pet(string.charAt(i))
|
|
}
|
|
|
|
.function _64spec_scr_to_pet(screencode) {
|
|
.var result = screencode
|
|
.if (screencode < 32) {
|
|
.return result + 64
|
|
}
|
|
.if (screencode < 64) {
|
|
.return result
|
|
}
|
|
.if (screencode < 95) {
|
|
.return result + 128
|
|
}
|
|
.if (screencode == 95) { // underscore
|
|
.return 164
|
|
}
|
|
.if (screencode < 128) {
|
|
.return result + 64
|
|
}
|
|
.if (screencode < 160) {
|
|
.return result - 128
|
|
}
|
|
.if (screencode < 224) {
|
|
.return result - 64
|
|
}
|
|
.return result
|
|
}
|
|
|
|
.macro _64spec_open_file_for_writing(string, logical_file_number) {
|
|
jmp end_filename
|
|
filename:
|
|
:_64spec_pet_text(string)
|
|
:_64spec_pet_text(",p,w")
|
|
end_filename:
|
|
|
|
:_64spec_kernal_setnam #[end_filename - filename]; #filename
|
|
:_64spec_kernal_setlfs #logical_file_number; #8; #2
|
|
:_64spec_kernal_open
|
|
}
|
|
|
|
.macro _64spec_close_file(logical_file_number) {
|
|
lda #logical_file_number
|
|
jsr _CLOSE
|
|
}
|
|
|
|
.macro _64spec_set_file_output(logical_file_number) {
|
|
ldx #logical_file_number
|
|
jsr _CHKOUT
|
|
}
|
|
|
|
.macro _64spec_set_screen_output() {
|
|
jsr _CLRCHN
|
|
}
|
|
|
|
|
|
.pseudocommand _64spec_kernal_setnam length; string_address {
|
|
lda length
|
|
ldx _64spec_extract_byte_argument(string_address, 0)
|
|
ldy _64spec_extract_byte_argument(string_address, 1)
|
|
jsr _SETNAM
|
|
}
|
|
.pseudocommand _64spec_kernal_setlfs logical_file_number; device_number; command {
|
|
lda logical_file_number
|
|
ldx device_number
|
|
ldy command
|
|
jsr _SETLFS
|
|
}
|
|
|
|
|
|
.pseudocommand _64spec_kernal_open {
|
|
jsr _OPEN
|
|
}
|
|
|
|
.pseudocommand _64spec_kernal_plot_get column; row {
|
|
sec
|
|
jsr _PLOT
|
|
.if (column.getType() != AT_NONE) {
|
|
stx row
|
|
}
|
|
.if (row.getType() != AT_NONE) {
|
|
sty column
|
|
}
|
|
}
|
|
.pseudocommand _64spec_kernal_plot_set column; row {
|
|
clc
|
|
ldx row
|
|
ldy column
|
|
jsr _PLOT
|
|
}
|