; The SuperconBadgeV6 Assembler ; https://hackaday.io/project/191355-assembler-for-superconbadge ; Version 0.1 - convert ASCII HEX (bigendian) code string to binary loader format ; This is a text version of the code, in no particular syntax. ; It is handassembled i.e. I write the address/hex code in here, and then button it into the badge ; ( potentially: convert to binary format in an editor by replacing ASCII with binary ... ) ; Overview functionality: ; Write header, convert the first 4 hexdigits(BigEndian) to the length field (LittleEndian) ; The convert hex 3-digits opcodes (BigEndian) to binary 2-byte (LittleEndian) ; Write trailer ie. the computed checksum (LittleEndian) Loc Code Inst --- --- -------... ; start 000 902 MOV R0,0x2 ; fast=2/slow=D clock. Changed as needed. 001 CF1 MOV [CLCK],R0 ; (also copied to padding sections where debugging) 002 90F MOV R0,0xF ; Page so we see the SER-registers and the R-registers 003 CF0 MOV [PAGE],R0 PURGE: 004 DF7 MOV R0,[SERH] ; purge any partial input (leftover from last run, noise ...) 005 DF6 MOV R0,[SERL] 006 DF8 MOV R0,[RCVD] ; really empty input buffer 007 000 CP R0,0 008 0F9 SKIP Z,1 009 FFA JR PURGE ; (unfortunatly this code doesn't do what is intended) 00A 888 MOV R8,R8 ; a few NOP for patch room whilst debugging 00B 888 00C 888 00D 888 00E 888 00F 888 ; Output leading bytes of header - (could rewrite to loops with lookup) 010 E07 MOV PC,PUTBIN ; (@070) output binary R1 value 011 910 MOV R1,0 ; Value=0 012 9C0 MOV JSR,0 ; call output it 013 9C0 MOV JSR,0 ; twice, ie output 00 014 91F MOV R1,0xF ; Value=F 015 9C0 MOV JSR,0 016 9C0 MOV JSR,0 ; twice, ie output FF 017 910 MOV R1,0 ; repeat to do another 00FF 018 9C0 MOV JSR,0 019 9C0 MOV JSR,0 01A 91F MOV R1,0xF 01B 9C0 MOV JSR,0 01C 9C0 MOV JSR,0 01D 91A MOV R1,0xA ; and output A5C3 01E 9C0 MOV JSR,0 01F 915 MOV R1,0x5 020 9C0 MOV JSR,0 021 91C MOV R1,0xC 022 9C0 MOV JSR,0 023 913 MOV R1,0x3 024 9C0 MOV JSR,0 025 888 MOV R8,R8 ;Two nops for debugging room 026 888 MOV R8,R8 ; Next the length byte - for now required in the user input, although part of the header. ; is entered "normally", ie BigEndian, with 4 digits ; initialise checksum with this 027 E08 MOV PC,GETHEX ; call read HEX (@080) into R1 028 9C0 MOV JSR,0 029 891 MOV R9,R1 ; save highest nibble 02A 9C0 MOV JSR,0 02B 881 MOV R8,R1 ; do other 3... 02C 9C0 MOV JSR,0 02D 871 MOV R7,R1 02E 9C0 MOV JSR,0 02F 861 MOV R6,R1 030 E07 MOV PC,PUTBIN ; Output in LittleEndian order 031 817 MOV R1,R7 ; Top nibble of low byte 032 9C0 MOV JSR,0 033 816 MOV R1,R6 ; Low nibble of low byte 034 9C0 MOV JSR,0 035 819 MOV R1,R9 ; Top nibble of top byte 036 9C0 MOV JSR,0 037 818 MOV R1,R8 ; Low nibble of top byte 038 9C0 MOV JSR,0 039 888 MOV R8,R8 ; couple of NOPs ... 03A 888 MOV R8,R8 ; now loop reading 3 ASCII HEX normal/bigendian, and outputting two bytes, littleendian. ; END is signalled by the ^D(EOT). The Hex input routine catches it and returns R0=F LOOP: 03B E08 MOV PC,GETHEX 03C 9C0 MOV JSR,0 03D 00F CP R0,0xF ; did we see EOT 03E 0FD SKIP NZ,1 ; 03F F18 JR TRAIL ; 058-040=18 - EOT => do trailer 040 841 MOV R4,R1 ; Save high nibble 041 9C0 MOV JSR,0 042 831 MOV R3,R1 ; save middle nibble 043 9C0 MOV JSR,0 044 821 MOV R2,R1 ; save lower nibble 045 E07 MOV PC,PUTBIN ; 046 813 MOV R1,R3 ; Middle nibble 047 9C0 MOV JSR,0 048 812 MOV R1,R2 ; low nibble 049 9C0 MOV JSR,0 04A 910 MOV R1,0 ; padding byte, zero 04B 9C0 MOV JSR,0 04C 814 MOV R1,R4 ; high nibble 04D 9C0 MOV JSR,0 04E 888 MOV R8,R8 ; a few NOP for patch room whilst debugging 04F 888 ; accumulate checksum in R9:8:7:6 050 162 ADD R6,R2 ; Accumulate the number, right way up 051 273 ADC R7,R3 052 284 ADC R8,R4 053 900 MOV R0,0 ; the paddding zero 054 290 ADC R9,R0 ; to include the carry ; Loop 055 025 INC R5 ; (Debugging, we see number of doublebytes output in R5) 056 FE4 JR LOOP ; 03B-057=E4 057 000 ; filler (never executes here) ; do the trailer TRAIL: 058 E07 MOV PC,PUTBIN ; call output binary R1 value 059 817 MOV R1,R7 ; output the checksum, LittleEndian 05A 9C0 MOV JSR,0 05B 816 MOV R1,R6 ; 05C 9C0 MOV JSR,0 05D 819 MOV R1,R9 ; 05E 9C0 MOV JSR,0 05F 818 MOV R1,R8 ; 060 9C0 MOV JSR,0 061 888 MOV R8,R8 062 FFF HALT ; Actually jump back to itself. ; Could also do a RET, as the stack is empty and it will really halt 063 000 ; the loader doesn't support skipping, so the file has to contain something, here zeros. 064 000 065 000 066 000 067 000 068 000 069 000 06A 000 06B 000 06C 000 06D 000 06E 000 06F 000 PUTBIN: ; output a binary nibble. It buffers so two nibbles, first high, then low, make one byte ; Entry: R1=nibble ; Exit: R0=0 on first nibble, R0=1 on 2nd nibble ; Global: FLAG at [0x20], BUFOUT at [0x21] 070 D20 MOV R0,[FLAG] ; Get flag 071 000 CP R0,0 ; 072 801 MOV R0,R1 ; (doesnt disturb the CP result) 073 0FC SKIP NZ,4 ; Flag set, skip to output byte 074 C21 MOV [BUFOUT],R0; else store in buffer 075 90F MOV R0,0xF ; and set flag 076 C20 MOV [FLAG],R0 077 0E1 RET R0,1 078 D21 MOV R0,[BUFOUT]; Get buffered nibble 079 CF7 MOV [SERH],R0 ; output it 07A 801 MOV R0,R1 07B CF6 MOV [SERL],R0 ; Output lower nibble, byte is sent 07C 900 MOV R0,0 ; reset flag 07D C20 MOV [FLAG],R0 07E 0E0 RET R0,0 07F 000 ;(filler) GETHEX: ; get binary value of ASCII HEX character from input. Must be uppercase, no whitespace ; Entry: - ; Exit: R0=0 : R1 value of digit, R0=F it is a control char and R1 invalid 080 DF8 MOV R0,[RCVD] ; Is anything in input? 081 000 CP R0,0 082 0FD SKIP NZ,1 083 FFC JR GETHEX ; 080-084=FC 084 910 MOV R1,0 ; Assume a 0-9 085 DF7 MOV R0,[SERH] ; Get char high 086 004 CP R0,4 ; Is A..F or 0..9 087 0FD SKIP NZ,1 088 919 MOV R1,9 ; Adjust so low('A')=1 returns 10(10) 089 000 CP R0,0 ; is it a LOW control character (eg TAB,CR ^D(EOT)) 08A 0FB SKIP Z,3 ; yes (we dont care which) 08B DF6 MOV R0,[SERL] ; low nibble is the value (+ the 9 for A..Z) 08C 110 ADD R1,R0 08D 0E0 RET R0,0 08E DF6 MOV R0,[SERL] ; get the rest of char (should check if 0x4) 08F 0EF RET R0,0xF ; Signal end.