Added the unary + operator, and cleaned up the display of values from the expression parser
This commit is contained in:
parent
5fa958dfea
commit
127ddb88b4
7 changed files with 1006 additions and 817 deletions
|
|
@ -5,14 +5,15 @@ date: 2017-02-28 22:00:00
|
|||
permalink: /blog/2017/02/28/
|
||||
---
|
||||
|
||||
Since I've more or less achieved all my goals for the PCjs [PDP-11 Emulator](/devices/pdp11/machine/), I've decided
|
||||
to turn my attention to an even older historically important DEC computer: the [PDP-10](https://en.wikipedia.org/wiki/PDP-10#Cancellation_and_influence).
|
||||
Since I've more or less achieved all my goals for the PCjs [PDP-11 Emulator](/devices/pdp11/machine/),
|
||||
I've decided to turn my attention to an even older historically important DEC computer:
|
||||
the [PDP-10](https://en.wikipedia.org/wiki/PDP-10#Cancellation_and_influence).
|
||||
|
||||
Having never used a real DEC PDP-10, I've had a steep learning curve creating a [PDP-10 Emulator](/modules/pdp10/).
|
||||
So far, the only [PDP-10 Hardware Documentation](/pubs/dec/pdp10/) I've read (or rather, skimmed) is the
|
||||
[PDP-10 System Reference Manual (1968)](http://archive.pcjs.org/pubs/dec/pdp10/ka10/DEC-10-HGAA-D_PDP-10_System_Reference_Manual_May1968.pdf).
|
||||
|
||||
To make it easier to create and run some simple [PDP-10 Opcode Tests](/apps/pdp10/tests/), most of my initial development
|
||||
To make it easier to create and run some simple [PDP-10 Opcode Tests](/apps/pdp10/tests/opcodes/), most of my initial development
|
||||
efforts have centered on the built-in PDP-10 Debugger. In addition to the usual disassembler capabilities, I've also included
|
||||
an assembler, so that I can easily enter instruction sequences like this:
|
||||
|
||||
|
|
@ -34,7 +35,7 @@ and immediately see the corresponding opcodes:
|
|||
It's not a full-featured assembler; it's little more than a brute-force reverse look-up through the disassembler's
|
||||
opcode-to-mnemonic tables. But it gets the job done.
|
||||
|
||||
Next, I've written an initial set of [PDP-10 Opcode Tests](/apps/pdp10/tests/) and compared the results to those produced
|
||||
Next, I've written an initial set of [PDP-10 Opcode Tests](/apps/pdp10/tests/opcodes/) and compared the results to those produced
|
||||
by [SIMH](https://github.com/simh/simh), and so far, so good. More than anything else, that's just a testament to DEC's
|
||||
excellent documentation.
|
||||
|
||||
|
|
|
|||
184
_posts/2017-03-21-the-macro-10-assembler-50-years-later.md
Normal file
184
_posts/2017-03-21-the-macro-10-assembler-50-years-later.md
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
---
|
||||
layout: post
|
||||
title: The MACRO-10 Assembler, 50 Years Later
|
||||
date: 2017-02-28 22:00:00
|
||||
permalink: /blog/2017/03/21/
|
||||
machines:
|
||||
- id: testka10
|
||||
type: pdp10
|
||||
config: /devices/pdp10/machine/ka10/test/debugger/machine.xml
|
||||
debugger: true
|
||||
commands: a 30724 /apps/pdp10/diags/klad/dakaa/MYDAKAA.MAC
|
||||
---
|
||||
|
||||
A few weeks ago, I finished my first cut of the *core* PDP-10 instructions in PDPjs. Most of my remaining work
|
||||
falls into these categories:
|
||||
|
||||
- UUOs (Unimplemented User Operations)
|
||||
- Floating-point instructions
|
||||
- Input-Output instructions (eg, BLKI, BLKO, DATAI, DATAO)
|
||||
- Miscellaneous instructions (eg, variations of PUSH, POP, JUMP)
|
||||
|
||||
Floating-point is the biggest chunk of work, which I'm going to save for last, with the hope that most PDP-10 software
|
||||
didn't use floating-point. However, if all PDP-10 systems included floating-point hardware (which I haven't been able to
|
||||
confirm yet), I may have no choice. Floating-point emulation in JavaScript isn't hard -- PCjs already includes an
|
||||
[8087 Coprocessor Emulator](/modules/pcx86/lib/x86fpu.js) -- but getting all the details right is time-consuming.
|
||||
|
||||
The PDP-10 has a lot of instructions, and I quickly had far more instructions than I was willing or able to write tests for.
|
||||
Besides, any tests I wrote would be based on the same potentially-flawed understandings that I had gleaned from DEC's
|
||||
[PDP-10 Hardware Documentation](/pubs/dec/pdp10/). It was obvious that I needed to find a set of DEC PDP-10 diagnostics, much
|
||||
like the [DEC PDP-11 Paper Tape Diagnostics](/apps/pdp11/tapes/diags/) I had used to flush most of the early bugs out of my
|
||||
PDP-11 emulator.
|
||||
|
||||
Unfortunately, this presented something of a chicken-and-egg problem, because the PDP-10 emulator is still too immature to
|
||||
support any simulated devices, even something as simple as paper tape. However, since I did find a series of PDP-10 Model KA10
|
||||
diagnostics in [source code form](http://pdp-10.trailing-edge.com/klad_sources/), all I needed was some way to assemble those
|
||||
files into binaries that I could load directly in a PDPjs test machine.
|
||||
|
||||
One solution would have been to run a TOPS-10 simulation using the SIMH emulator, assemble the desired tests inside that virtual
|
||||
machine, extract the binaries, and then load them into a PDPjs machine. But that would have meant familiarizing myself with
|
||||
both SIMH and TOPS-10, and the process of editing, assembling, and transferring binaries to PDPjs would have been cumbersome at
|
||||
best.
|
||||
|
||||
### Introducing the MACRO-10 "Mini-Assembler"
|
||||
|
||||
I decided that the shortest turn-around from *assembly* phase to *run* phase (aka *crash-and-burn* phase) would be to
|
||||
assemble the files in PDPjs itself. So the PDPjs MACRO-10 "Mini-Assembler" was born. Any machine that includes the PDPjs
|
||||
Debugger (like the machine below) now includes MACRO-10 support as well.
|
||||
|
||||
{% include machine.html id="testka10" %}
|
||||
|
||||
The above machine uses the Debugger's assemble ('a') command to assemble DEC's "DAKAA" diagnostic
|
||||
[KA10 Basic Instruction Diagnostic](/apps/pdp10/diags/klad/dakaa/) and load the resulting code at address 30724:
|
||||
|
||||
a 30724 /apps/pdp10/diags/klad/dakaa/MYDAKAA.MAC
|
||||
|
||||
The Debugger invokes the MACRO-10 mini-assembler whenever the argument following the target address appears to be a URL.
|
||||
|
||||
As previously described in the section on [PDPjs PDP-10 Opcode Tests](/apps/pdp10/tests/opcodes/), the Debugger already
|
||||
allowed you to assemble instructions directly into memory (eg, `a 100 hrli 1,111111`). This "immediate mode" feature is provided
|
||||
exclusively by the Debugger; MACRO-10 mini-assembler features are not available in that mode.
|
||||
|
||||
However, one feature that *is* available in both the Debugger and the mini-assembler is full MACRO-10-style expression evaluation,
|
||||
since they share the same expression parser. Here are some examples, using the Debugger's 'print' command:
|
||||
|
||||
>> print 27
|
||||
23. 0o000027
|
||||
|
||||
Both the Debugger and MACRO-10 start out by assuming a default base (radix) of 8, so the value "27" is evaluated as an octal
|
||||
number, and for convenience, the "print" command displays the result in both decimal and octal. You can change the default base
|
||||
in the Debugger with the `s base` command (eg, `s base 10`), where the new base is always interpreted as a decimal number.
|
||||
This command differs from MACRO-10, which uses the `RADIX` pseudo-op to change the default base.
|
||||
|
||||
Obviously, it would be nice if both the Debugger and the MACRO-10 mini-assembler used matching commands, but the PCjs debuggers
|
||||
were written before MACRO-10 support was a consideration, so for now, that's life.
|
||||
|
||||
All of the MACRO-10-style base prefixes are supported (^D for decimal, ^B for binary, an ^O for octal):
|
||||
|
||||
>> print ^D27
|
||||
0o000000000033 27.
|
||||
|
||||
>> print ^B1001
|
||||
0o000000000011 9.
|
||||
|
||||
>> print ^O1001
|
||||
0o000000001001 513.
|
||||
|
||||
Expressions using angle brackets, another MACRO-10 convention, is also supported:
|
||||
|
||||
>> print ^D<45-22>
|
||||
0o000000000027 23.
|
||||
|
||||
Note that the base modifier (^D) applies to the entire expression. You can also add MACRO-10 suffixes to integers:
|
||||
|
||||
K: "kilo-", thousands
|
||||
M: "mega-", millions
|
||||
G: "giga-", billions
|
||||
|
||||
so:
|
||||
|
||||
>> print 5K
|
||||
0o000000005000 2560.
|
||||
|
||||
>> print ^D5K
|
||||
0o000000011610 5000.
|
||||
|
||||
Binary shifting using a B suffix is also supported:
|
||||
|
||||
>> print 1B0
|
||||
0o400000000000 -34359738368.
|
||||
|
||||
>> print 1B17
|
||||
0o000001000000 262144.
|
||||
|
||||
>> print 1B35
|
||||
0o000000000001 1.
|
||||
|
||||
>> print -1B35
|
||||
0o777777777777 -1.
|
||||
|
||||
>> print -1B53
|
||||
0o000000777777 262143.
|
||||
|
||||
>> print -1B70
|
||||
0o000000000001 1.
|
||||
|
||||
And as the MACRO-10 ASSEMBLER PROGRAMMER'S REFERENCE MANUAL (June 1972), p. 1-17, points out, all the following expressions are
|
||||
equivalent:
|
||||
|
||||
>> print 10B32
|
||||
0o000000000100 64. '@'
|
||||
|
||||
>> print ^O10B32
|
||||
0o000000000100 64. '@'
|
||||
|
||||
>> print 10B<42-10>
|
||||
0o000000000100 64. '@'
|
||||
|
||||
>> print 10B<^D<42-10>>
|
||||
0o000000000100 64. '@'
|
||||
|
||||
>> print 10B<^D42-^D10>
|
||||
0o000000000100 64. '@'
|
||||
|
||||
"Left arrow" shifting is also supported, although the character that the original MACRO-10 manuals referred to as a "left arrow"
|
||||
is actually an underscore; later manuals refer to this as "underscore shifting":
|
||||
|
||||
>> print 1_^D18
|
||||
0o000001000000 262144.
|
||||
|
||||
>> print -1_^D-18
|
||||
0o000000777777 262143.
|
||||
|
||||
Character-based constants are also supported, in the both 7-bit ASCII the 6-bit SIXBIT formats. Use double-quotes
|
||||
for 7-bit right-justified character constants and single-quotes for 6-bit right-justified character constants:
|
||||
|
||||
>> print +'SIXBIT'
|
||||
0o635170425164 -13255955852.
|
||||
|
||||
>> print +"HELLO"
|
||||
0o221054623117 19473311311.
|
||||
|
||||
NOTE: When using the PCjs debugger, the constant must be preceded by an arithmetic operator, otherwise it interprets the
|
||||
quoted argument as a string. This is an idiosyncrasy of the "print" command, not the expression parser.
|
||||
|
||||
All MACRO-10 logical and arithmetic operators are supported, including:
|
||||
|
||||
- Unary arithmetic operators (+ and -)
|
||||
- Unary complement operator (^-, aliased to ~)
|
||||
- Unary base overrides (^D, ^O, and ^B)
|
||||
- Binary shifting (B) and underscore shifting (_) operators
|
||||
- Logical binary operations (! for OR, ^! for XOR, and & for AND)
|
||||
- Multiplication and division (* and /)
|
||||
- Addition and subtraction (+ and -)
|
||||
- Angle brackets for expression grouping (< and >)
|
||||
|
||||
Much more work is needed to make the MACRO-10 "Mini-Assembler" a general-purpose assembler, but it's already proved itself
|
||||
useful in assembling the following tests:
|
||||
|
||||
- [KA10 Basic Instruction Diagnostic #1](/apps/pdp10/diags/klad/dakaa/)
|
||||
- [KA10 Basic Instruction Diagnostic #4](/apps/pdp10/diags/klad/dakad/)
|
||||
- [Assorted MACRO-10 Mini-Assembler Tests](/apps/pdp10/tests/macro10/)
|
||||
|
||||
*[@jeffpar](http://twitter.com/jeffpar)*
|
||||
*Mar 21, 2017*
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
layout: page
|
||||
title: DEC Paper Tape Diagnostics
|
||||
title: DEC PDP-11 Paper Tape Diagnostics
|
||||
permalink: /apps/pdp11/tapes/diags/
|
||||
---
|
||||
|
||||
Paper Tape Diagnostics
|
||||
----------------------
|
||||
PDP-11 Paper Tape Diagnostics
|
||||
-----------------------------
|
||||
|
||||
Thanks to the [iamvirtual.ca](http://iamvirtual.ca/collection/systems/mediadoc/mediadoc.html#papertape)
|
||||
website, we have been able to archive the PDP-11 diagnostics shown below. The tapes have been added to the
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -52,7 +52,7 @@ y:121,z:122,"{":123,"|":124,"}":125,"~":126,po:127},ma={};ma[173]=n["-"];ma[186]
|
|||
p[192]=n["~"];p[219]=n["{"];p[220]=n["|"];p[221]=n["}"];p[222]=n['"'];p[173]=n._;p[61]=n["+"];p[59]=n[":"];
|
||||
function na(a,b){var c;if(a){b||(b=10);var d,e,f=0<a.indexOf(",");f&&(a=a.replace(/,/g,""));d=e=a.charAt(0);"#"==e?(b=8,e=""):"$"==e&&(b=16,e="");d!=e?a=a.substr(1):(d=e=a.substr(0,2),"0b"==e&&f||"^B"==e?(b=2,e=""):"0o"==e||"^O"==e?(b=8,e=""):"^D"==e?(b=10,e=""):"0x"==e&&(b=16,e=""),d!=e&&(a=a.substr(2)));d=e=a.slice(-1);"Y"==e||"y"==e?(b=2,e=""):"."==e?(b=10,e=""):"H"==e||"h"==e?(b=16,e=""):"K"==e?e="000":"M"==e?e="000000":"G"==e&&(e="000000000");d!=e&&(a=a.slice(0,-1)+e);var g;d=0;if(e=a.match(/(-?[0-9]+)B([0-9]*)/))a=
|
||||
e[1],d=35-((e[2]||35)&255);e=a;((f=b)&&10!=f?16==f?e.match(/^-?[0-9a-f]+$/i):8==f?e.match(/^-?[0-7]+$/):2==f&&e.match(/^-?[01]+$/):e.match(/^-?[0-9]+$/))&&!isNaN(g=parseInt(a,b))&&(d&&(0>g&&(g+=Math.pow(2,36)),g=0<d?g*Math.pow(2,d):Math.trunc(g/Math.pow(2,-d))),c=g)}return c}
|
||||
function oa(a,b,c){b?9<b&&(b=9):(b=Math.abs(a),b=65535>=b?4:4294967295>=b?8:9);c=c?"0x":"";var d;d=void 0===d?-1:d;var e="";isNaN(a)?a=null:null!=a&&(0>a&&-1<a&&(a=-1),0>a&&(a+=Math.pow(16,b)),a>=Math.pow(16,b)&&(b=Math.ceil(Math.log(a)/Math.log(16))));for(var f=d;0<b--;){f||(e=","+e,f=d);if(null==a)e="?"+e;else{var g=a%16,g=g+(0<=g&&9>=g?48:55),e=String.fromCharCode(g)+e;a=Math.trunc(a/16)}f--}return(void 0===c?"":c)+e}
|
||||
function oa(a,b,c){b?9<b&&(b=9):(b=Math.abs(a),b=65535>=b?4:4294967295>=b?8:9);c=c?"0x":"";var d;d=void 0===d?0:d;var e="";isNaN(a)?a=null:null!=a&&(0>a&&-1<a&&(a=-1),0>a&&(a+=Math.pow(16,b)),a>=Math.pow(16,b)&&(b=Math.ceil(Math.log(a)/Math.log(16))));for(var f=d||-1;0<b--;){f||(e=","+e,f=d);if(null==a)e="?"+e;else{var g=a%16,g=g+(0<=g&&9>=g?48:55),e=String.fromCharCode(g)+e;a=Math.trunc(a/16)}f--}return(void 0===c?"":c)+e}
|
||||
function pa(a,b){var c=a,d=a.lastIndexOf("/");0<=d&&(c=a.substr(d+1));d=c.indexOf("&");0<d&&(c=c.substr(0,d));b&&(d=c.lastIndexOf("."),0<d&&(c=c.substring(0,d)));return c}function qa(a){var b="",c=a.lastIndexOf(".");0<=c&&(b=a.substr(c+1).toLowerCase());return b}function ra(a,b){return-1!==a.indexOf(b,a.length-b.length)}function sa(a){return a.replace(/[&<>"']/g,function(a){return ta[a]})}function ua(a){return String.prototype.trim?a.trim():a.replace(/^\s+|\s+$/g,"")}
|
||||
var ta={"&":"&","<":"<",">":">",'"':""","'":"'"},va={0:"NUL",1:"SOH",2:"STX",3:"ETX",4:"EOT",5:"ENQ",6:"ACK",7:"BEL",8:"BS",9:"TAB",10:"LF",11:"VT",12:"FF",13:"CR",14:"SO",15:"SI",16:"DLE",17:"XON",18:"DC2",19:"XOFF",20:"DC4",21:"NAK",22:"SYN",23:"ETB",24:"CAN",25:"EM",26:"SUB",27:"ESC",28:"FS",29:"GS",30:"RS",31:"US"};
|
||||
function wa(){function a(a){return(10>a?"0":"")+a}var b=new Date;return b.getFullYear()+"-"+a(b.getMonth()+1)+"-"+a(b.getDate())+" "+a(b.getHours())+":"+a(b.getMinutes())+":"+a(b.getSeconds())}function xa(a,b){var c=0,d=1,e;for(e in a){if(d>=arguments.length)break;var f=a[e],g=arguments[d++],c=c&~f.qg|g<<f.shift&f.qg}return c}function ya(a,b){return(b&a.qg)>>a.shift}var za=[31,28,31,30,31,30,31,31,30,31,30,31],Aa=Date.now||function(){return+new Date};
|
||||
|
|
|
|||
|
|
@ -673,6 +673,9 @@ class Debugger extends Component
|
|||
continue;
|
||||
}
|
||||
if (!(nUnary & (0xC0000000|0))) {
|
||||
if (sOp == '+') {
|
||||
continue;
|
||||
}
|
||||
if (sOp == '-') {
|
||||
nUnary = (nUnary << 2) | 1;
|
||||
continue;
|
||||
|
|
@ -1020,9 +1023,9 @@ class Debugger extends Component
|
|||
if (value !== undefined) {
|
||||
fDefined = true;
|
||||
if (this.nBase == 8) {
|
||||
sValue = value + ". " + Str.toOct(value, 0, true);
|
||||
sValue = this.toStrBase(value, this.nBits, 8, 1) + " " + value + '.';
|
||||
} else {
|
||||
sValue = Str.toHex(value, 0, true) + " " + value + ". " + Str.toOct(value, 0, true) + " " + Str.toBinBytes(value, 4, true);
|
||||
sValue = this.toStrBase(value, this.nBits, 16, 1) + " " + this.toStrBase(value, this.nBits, 8, 1) + " " + this.toStrBase(value, this.nBits, 2, this.nBits <= 32? 8 : 6) + " " + value + '.';
|
||||
}
|
||||
if (value >= 0x20 && value < 0x7F) {
|
||||
sValue += " '" + String.fromCharCode(value) + "'";
|
||||
|
|
@ -1113,24 +1116,26 @@ class Debugger extends Component
|
|||
}
|
||||
|
||||
/**
|
||||
* toStrBase(n, nBits)
|
||||
* toStrBase(n, nBits, nBase, nGrouping)
|
||||
*
|
||||
* Use this instead of Str's toOct()/toDec()/toHex() to convert numbers to the Debugger's default base.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number|null|undefined} n
|
||||
* @param {number} [nBits] (-1 to strip leading zeros, 0 to allow a variable number of digits)
|
||||
* @param {number} [nBase]
|
||||
* @param {number} [nGrouping] (if nBase is 2, this is a grouping; otherwise, it's a prefix condition)
|
||||
* @return {string}
|
||||
*/
|
||||
toStrBase(n, nBits = 0)
|
||||
toStrBase(n, nBits = 0, nBase = 0, nGrouping = 0)
|
||||
{
|
||||
var s;
|
||||
switch(this.nBase) {
|
||||
switch(nBase || this.nBase) {
|
||||
case 2:
|
||||
s = Str.toBin(n, nBits > 0? nBits : 0);
|
||||
s = Str.toBin(n, nBits > 0? nBits : 0, nGrouping);
|
||||
break;
|
||||
case 8:
|
||||
s = Str.toOct(n, nBits > 0? ((nBits + 2)/3)|0 : 0);
|
||||
s = Str.toOct(n, nBits > 0? ((nBits + 2)/3)|0 : 0, !!nGrouping);
|
||||
break;
|
||||
case 10:
|
||||
/*
|
||||
|
|
@ -1140,7 +1145,7 @@ class Debugger extends Component
|
|||
break;
|
||||
case 16:
|
||||
default:
|
||||
s = Str.toHex(n, nBits > 0? ((nBits + 3) >> 2) : 0);
|
||||
s = Str.toHex(n, nBits > 0? ((nBits + 3) >> 2) : 0, !!nGrouping);
|
||||
break;
|
||||
}
|
||||
return (nBits < 0? Str.stripLeadingZeros(s) : s);
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ class Str {
|
|||
}
|
||||
|
||||
/**
|
||||
* toBase(n, radix, cch, sPrefix, grouping)
|
||||
* toBase(n, radix, cch, sPrefix, nGrouping)
|
||||
*
|
||||
* Displays the given number as an unsigned integer using the specified radix and number of digits.
|
||||
*
|
||||
|
|
@ -187,10 +187,10 @@ class Str {
|
|||
* @param {number} radix (ie, the base)
|
||||
* @param {number} cch (the desired number of digits)
|
||||
* @param {string} [sPrefix] (default is none)
|
||||
* @param {number} [grouping]
|
||||
* @param {number} [nGrouping]
|
||||
* @return {string}
|
||||
*/
|
||||
static toBase(n, radix, cch, sPrefix = "", grouping = -1)
|
||||
static toBase(n, radix, cch, sPrefix = "", nGrouping = 0)
|
||||
{
|
||||
/*
|
||||
* An initial "falsey" check for null takes care of both null and undefined;
|
||||
|
|
@ -222,11 +222,11 @@ class Str {
|
|||
cch = Math.ceil(Math.log(n) / Math.log(radix));
|
||||
}
|
||||
}
|
||||
var g = grouping;
|
||||
var g = nGrouping || -1;
|
||||
while (cch-- > 0) {
|
||||
if (!g) {
|
||||
s = ',' + s;
|
||||
g = grouping;
|
||||
g = nGrouping;
|
||||
}
|
||||
if (n == null) {
|
||||
s = '?' + s;
|
||||
|
|
@ -242,16 +242,16 @@ class Str {
|
|||
}
|
||||
|
||||
/**
|
||||
* toBin(n, cch, grouping)
|
||||
* toBin(n, cch, nGrouping)
|
||||
*
|
||||
* Converts an integer to binary, with the specified number of digits (up to a maximum of 36).
|
||||
*
|
||||
* @param {number|null|undefined} n (supports integers up to 36 bits now)
|
||||
* @param {number} [cch] is the desired number of binary digits (0 or undefined for default of either 8, 18, or 36)
|
||||
* @param {number} [grouping]
|
||||
* @param {number} [nGrouping]
|
||||
* @return {string} the binary representation of n
|
||||
*/
|
||||
static toBin(n, cch, grouping)
|
||||
static toBin(n, cch, nGrouping)
|
||||
{
|
||||
if (!cch) {
|
||||
// cch = Math.ceil(Math.log(Math.abs(n) + 1) / Math.LN2) || 1;
|
||||
|
|
@ -264,7 +264,7 @@ class Str {
|
|||
cch = 36;
|
||||
}
|
||||
} else if (cch > 36) cch = 36;
|
||||
return Str.toBase(n, 2, cch, "", grouping);
|
||||
return Str.toBase(n, 2, cch, "", nGrouping);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue