{"id":2982,"date":"2021-07-29T23:46:10","date_gmt":"2021-07-29T20:46:10","guid":{"rendered":"https:\/\/demensdeum.com\/blog\/?p=2982"},"modified":"2024-12-16T22:32:23","modified_gmt":"2024-12-16T19:32:23","slug":"writing-stuff-in-assembly-for-sega-genesis-3","status":"publish","type":"post","link":"https:\/\/demensdeum.com\/blog\/pt\/2021\/07\/29\/writing-stuff-in-assembly-for-sega-genesis-3\/","title":{"rendered":"Escrevendo em Assembly para Sega Genesis #3"},"content":{"rendered":"<p>Neste post irei descrever como exibir uma imagem de blocos no emulador Sega Genesis usando assembler.<br \/>A imagem inicial do <strong>Demens Deum<\/strong> no emulador Exodus ter\u00e1 esta apar\u00eancia:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2983\" src=\"https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2021\/07\/logo.png\" alt=\"\" width=\"804\" height=\"652\" srcset=\"https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2021\/07\/logo.png 804w, https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2021\/07\/logo-300x243.png 300w, https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2021\/07\/logo-768x623.png 768w\" sizes=\"auto, (max-width: 804px) 100vw, 804px\" \/><\/p>\n<p>O processo de sa\u00edda de uma imagem PNG usando blocos \u00e9 feito passo a passo:<\/p>\n<ol>\n<li>Reduzindo a imagem para o tamanho da tela do Shogi<\/li>\n<li>Converta PNG em c\u00f3digo de dados assembly, separado em cores e blocos<\/li>\n<li>Carregando uma paleta de cores no CRAM<\/li>\n<li>Carregando blocos\/padr\u00f5es na VRAM<\/li>\n<li>Carregando \u00edndices de blocos em endere\u00e7os do plano A\/B na VRAM<\/li>\n<li>Voc\u00ea pode reduzir a imagem para o tamanho da tela do Shogi usando seu editor gr\u00e1fico favorito, como o Blender.<\/li>\n<\/ol>\n<h3>Convers\u00e3o de PNG<\/h3>\n<p>Para converter imagens, voc\u00ea pode usar a ferramenta ImaGenesis; para trabalhar no wine, s\u00e3o necess\u00e1rias bibliotecas Visual Basic 6, elas podem ser instaladas usando winetricks (winetricks vb6run), ou RICHTX32.OCX pode ser baixado da Internet e colocado em a pasta do aplicativo para opera\u00e7\u00e3o correta.< \/p><\/p>\n<p>No ImaGenesis voc\u00ea precisa selecionar cores de 4 bits, exportar cores e blocos para dois arquivos no formato assembler. A seguir, no arquivo com cores, voc\u00ea precisa colocar cada cor em uma palavra (2 bytes), para isso utiliza o opcode dc.w.<\/p>\n<p>Por exemplo, tela inicial do CRAM:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>  dc.w $0000 \n  dc.w $0000 \n  dc.w $0222 \n  dc.w $000A \n  dc.w $0226 \n  dc.w $000C \n  dc.w $0220 \n  dc.w $08AA \n  dc.w $0446 \n  dc.w $0EEE \n  dc.w $0244 \n  dc.w $0668 \n  dc.w $0688 \n  dc.w $08AC \n  dc.w $0200 \n  dc.w $0000 \n<\/code><\/pre>\n<\/div>\n<p>Deixe o arquivo de blocos como est\u00e1, ele j\u00e1 cont\u00e9m o formato correto para carregamento. Exemplo de parte de um arquivo de blocos:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>\tdc.l\t$11111111\t; Tile #0 \n\tdc.l\t$11111111 \n\tdc.l\t$11111111 \n\tdc.l\t$11111111 \n\tdc.l\t$11111111 \n\tdc.l\t$11111111 \n\tdc.l\t$11111111 \n\tdc.l\t$11111111 \n\tdc.l\t$11111111\t; Tile #1 \n\tdc.l\t$11111111 \n\tdc.l\t$11111111 \n\tdc.l\t$11111111 \n\tdc.l\t$11111111 \n\tdc.l\t$11111111 \n\tdc.l\t$11111111 \n\tdc.l\t$11111111 \n<\/code><\/pre>\n<\/div>\n<p>Como voc\u00ea pode ver no exemplo acima, os blocos s\u00e3o uma grade 8&#215;8 que consiste em \u00edndices da paleta de cores CRAM.<\/p>\n<h3>Cores no CRAM<\/h3>\n<p>O carregamento na CRAM \u00e9 feito configurando um comando de carregamento de cores para um endere\u00e7o CRAM espec\u00edfico na porta de controle (controle vdp). O formato do comando est\u00e1 descrito no Sega Genesis Software Manual (1989), apenas acrescentarei que voc\u00ea s\u00f3 precisa adicionar 0x20000 ao endere\u00e7o para passar para a pr\u00f3xima cor.<\/p>\n<p>Em seguida voc\u00ea precisa carregar a cor na porta de dados (dados vdp); A maneira mais f\u00e1cil de entender o carregamento \u00e9 com o exemplo abaixo:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>    lea Colors,a0 ; pointer to Colors label \n    move.l #15,d7; colors counter \nVDPCRAMFillLoopStep: \n    move.l  d0,vdp_control_port ;  \n    move.w  (a0)+,d1; \n    move.w  d1,(vdp_data_port); \n    add.l #$20000,d0 ; increment CRAM address \n    dbra d7,VDPCRAMFillLoopStep \n<\/code><\/pre>\n<\/div>\n<h3>Telhas em VRAM<\/h3>\n<p>A seguir, carregamos blocos\/padr\u00f5es na mem\u00f3ria de v\u00eddeo VRAM. Para fazer isso, selecione um endere\u00e7o na VRAM, por exemplo 0x00000000. Por analogia com a CRAM, entramos em contato com a porta de controle VDP com um comando para escrever na VRAM e no endere\u00e7o inicial.<\/p>\n<p>Depois disso, voc\u00ea pode fazer upload de palavras longas para VRAM; em compara\u00e7\u00e3o com CRAM, n\u00e3o \u00e9 necess\u00e1rio especificar o endere\u00e7o de cada palavra longa, pois existe um modo de incremento autom\u00e1tico de VRAM. Voc\u00ea pode habilit\u00e1-lo usando o sinalizador de registro VDP 0x0F (dc.b $02)<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>  lea Tiles,a0 \n  move.l #$40200000,vdp_control_port; write to VRAM command \n  move.w #6136,d0 ; (767 tiles * 8 rows) counter \nTilesVRAMLoop: \n  move.l (a0)+,vdp_data_port; \n  dbra d0,TilesVRAMLoop \n<\/code><\/pre>\n<\/div>\n<h3>\u00cdndices de blocos no plano A\/B<\/h3>\n<p>Agora temos que preencher a tela com blocos de acordo com seu \u00edndice. Para isso, a VRAM \u00e9 preenchida no endere\u00e7o do Plano A\/B, que \u00e9 inserido nos registradores VDP (0x02, 0x04). Mais informa\u00e7\u00f5es sobre endere\u00e7amento complicado est\u00e3o no manual da Sega; no meu exemplo, o endere\u00e7o VRAM \u00e9 0xC000, vamos fazer upload dos \u00edndices l\u00e1.<\/p>\n<p>Sua imagem preencher\u00e1 o espa\u00e7o VRAM fora da tela de qualquer maneira, ent\u00e3o depois de desenhar o espa\u00e7o da tela, seu renderizador dever\u00e1 parar de desenhar e continuar novamente quando o cursor se mover para uma nova linha. Existem muitas op\u00e7\u00f5es de como implementar isso; usei a vers\u00e3o mais simples de contagem em dois registros do contador de largura da imagem e do contador de posi\u00e7\u00e3o do cursor.<\/p>\n<p>Exemplo de c\u00f3digo:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>  move.w #0,d0     ; column index \n  move.w #1,d1     ; tile index \n  move.l #$40000003,(vdp_control_port) ; initial drawing location \n  move.l #2500,d7     ; how many tiles to draw (entire screen ~2500) \n\nimageWidth = 31 \nscreenWidth = 64 \n\nFillBackgroundStep: \n  cmp.w\t#imageWidth,d0 \n  ble.w\tFillBackgroundStepFill \nFillBackgroundStep2: \n  cmp.w\t#imageWidth,d0 \n  bgt.w\tFillBackgroundStepSkip \nFillBackgroundStep3: \n  add #1,d0 \n  cmp.w\t#screenWidth,d0 \n  bge.w\tFillBackgroundStepNewRow \nFillBackgroundStep4: \n  dbra d7,FillBackgroundStep    ; loop to next tile \n\nStuck: \n  nop \n  jmp Stuck \n\nFillBackgroundStepNewRow: \n  move.w #0,d0 \n  jmp FillBackgroundStep4 \nFillBackgroundStepFill: \n  move.w d1,(vdp_data_port)    ; copy the pattern to VPD \n  add #1,d1 \n  jmp FillBackgroundStep2 \nFillBackgroundStepSkip: \n  move.w #0,(vdp_data_port)    ; copy the pattern to VPD \n  jmp FillBackgroundStep3 \n<\/code><\/pre>\n<\/div>\n<p>Depois disso, s\u00f3 falta montar a rom usando o vasm, iniciar o simulador e ver a foto.<\/p>\n<h3>Depura\u00e7\u00e3o<\/h3>\n<p>Nem tudo vai dar certo imediatamente, ent\u00e3o eu gostaria de recomendar as seguintes ferramentas do emulador Exodus:<\/p>\n<ol>\n<li>Depurador de processador M68k<\/li>\n<li>Alterando o n\u00famero de ciclos do processador m68k (para modo c\u00e2mera lenta no depurador)<\/li>\n<li>Visualizadores CRAM, VRAM, Plano A\/B<\/li>\n<li>Leia atentamente a documenta\u00e7\u00e3o do m68k, os opcodes usados \u200b\u200b(nem tudo \u00e9 t\u00e3o \u00f3bvio quanto parece \u00e0 primeira vista)<\/li>\n<li>Veja exemplos de c\u00f3digo\/desmontagem do jogo no github<\/li>\n<li>Implementar sub-rotinas de exce\u00e7\u00f5es do processador e process\u00e1-las<\/li>\n<\/ol>\n<p>Ponteiros para sub-rotinas de exce\u00e7\u00e3o do processador s\u00e3o colocados no cabe\u00e7alho da rom. H\u00e1 tamb\u00e9m um projeto no GitHub com um depurador de tempo de execu\u00e7\u00e3o interativo para Sega, chamado genesis-debugger.<\/p>\n<p>Use todas as ferramentas dispon\u00edveis, tenha uma boa codifica\u00e7\u00e3o \u00e0 moda antiga e que o <strong>Blast Processing<\/strong> esteja com voc\u00ea!<\/p>\n<h3>Links<\/h3>\n<p><a href=\"https:\/\/gitlab.com\/demensdeum\/segagenesissamples\/-\/tree\/main\/6Image\/vasm\" target=\"_blank\" rel=\"noopener\">https:\/\/gitlab.com\/demensdeum \/segagenesisamples\/-\/tree\/main\/6Image\/vasm<\/a><br \/><a href=\"http:\/\/devster.monkeeh.com\/sega\/imagenesis\/\" target=\"_blank\" rel=\"noopener\">http:\/\/devster.monkeeh.com\/sega\/imagenesis\/<\/a><br \/>\n<a href=\"https:\/\/github.com\/flamewing\/genesis-debugger\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/flamewing\/genesis-debugger<\/a><\/p>\n<h3>Fontes<\/h3>\n<p><a href=\"https:\/\/www.chibiakumas.com\/68000\/helloworld.php#LessonH5\" target=\"_blank\" rel=\"noopener\">https:\/\/www.chibiakumas.com\/68000\/helloworld .php#LessonH5<\/a><br \/><a href=\"https:\/\/huguesjohnson.com\/programming\/genesis\/tiles-sprites\/\" target=\"_blank\" rel=\"noopener\">https:\/\/huguesjohnson.com\/programming\/genesis\/tiles-sprites\/<\/a><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Neste post irei descrever como exibir uma imagem de blocos no emulador Sega Genesis usando assembler.A imagem inicial do Demens Deum no emulador Exodus ter\u00e1 esta apar\u00eancia: O processo de sa\u00edda de uma imagem PNG usando blocos \u00e9 feito passo a passo: Reduzindo a imagem para o tamanho da tela do Shogi Converta PNG em<a class=\"more-link\" href=\"https:\/\/demensdeum.com\/blog\/pt\/2021\/07\/29\/writing-stuff-in-assembly-for-sega-genesis-3\/\">Continue reading <span class=\"screen-reader-text\">&#8220;Escrevendo em Assembly para Sega Genesis #3&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[61,52],"tags":[165,172,174],"class_list":["post-2982","post","type-post","status-publish","format-standard","hentry","category-techie","category-tutorials","tag-asm","tag-roms","tag-vasm","entry"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"pt","enabled_languages":["en","ru","zh","de","fr","ja","pt","hi"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"ru":{"title":true,"content":true,"excerpt":false},"zh":{"title":true,"content":true,"excerpt":false},"de":{"title":true,"content":true,"excerpt":false},"fr":{"title":true,"content":true,"excerpt":false},"ja":{"title":true,"content":true,"excerpt":false},"pt":{"title":true,"content":true,"excerpt":false},"hi":{"title":false,"content":false,"excerpt":false}}},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/2982","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=2982"}],"version-history":[{"count":11,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/2982\/revisions"}],"predecessor-version":[{"id":3896,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/2982\/revisions\/3896"}],"wp:attachment":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=2982"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=2982"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=2982"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}